diff --git a/cmd/regup/app/update.go b/cmd/regup/app/update.go index 0768db43b..d5f7b9d10 100644 --- a/cmd/regup/app/update.go +++ b/cmd/regup/app/update.go @@ -16,7 +16,7 @@ import ( "github.com/stacklok/toolhive/pkg/container/verifier" "github.com/stacklok/toolhive/pkg/logger" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" ) var ( diff --git a/cmd/regup/app/update_test.go b/cmd/regup/app/update_test.go index f350ca5c0..2c4c62f6c 100644 --- a/cmd/regup/app/update_test.go +++ b/cmd/regup/app/update_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stacklok/toolhive/pkg/logger" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" ) //nolint:paralleltest // This test manages temporary directories and cannot run in parallel diff --git a/cmd/thv-operator/pkg/validation/image_validation.go b/cmd/thv-operator/pkg/validation/image_validation.go index 5f8384a77..be4e3f3f3 100644 --- a/cmd/thv-operator/pkg/validation/image_validation.go +++ b/cmd/thv-operator/pkg/validation/image_validation.go @@ -13,7 +13,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" ) // Sentinel errors for image validation. diff --git a/cmd/thv-operator/pkg/validation/image_validation_test.go b/cmd/thv-operator/pkg/validation/image_validation_test.go index 8e96544d1..1bb257c6a 100644 --- a/cmd/thv-operator/pkg/validation/image_validation_test.go +++ b/cmd/thv-operator/pkg/validation/image_validation_test.go @@ -13,7 +13,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" ) func TestAlwaysAllowValidator(t *testing.T) { diff --git a/cmd/thv-proxyrunner/app/run.go b/cmd/thv-proxyrunner/app/run.go index fa6e2b1d6..0809c2b3a 100644 --- a/cmd/thv-proxyrunner/app/run.go +++ b/cmd/thv-proxyrunner/app/run.go @@ -11,7 +11,7 @@ import ( "github.com/stacklok/toolhive/pkg/container" "github.com/stacklok/toolhive/pkg/container/runtime" "github.com/stacklok/toolhive/pkg/logger" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner" "github.com/stacklok/toolhive/pkg/workloads" ) diff --git a/cmd/thv/app/group.go b/cmd/thv/app/group.go index 902c3384b..3cdf7df29 100644 --- a/cmd/thv/app/group.go +++ b/cmd/thv/app/group.go @@ -16,7 +16,7 @@ import ( "github.com/stacklok/toolhive/pkg/core" "github.com/stacklok/toolhive/pkg/groups" "github.com/stacklok/toolhive/pkg/registry" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner/retriever" "github.com/stacklok/toolhive/pkg/transport" "github.com/stacklok/toolhive/pkg/validation" diff --git a/cmd/thv/app/registry.go b/cmd/thv/app/registry.go index 7dd572f7a..5b4303106 100644 --- a/cmd/thv/app/registry.go +++ b/cmd/thv/app/registry.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" "github.com/stacklok/toolhive/pkg/registry" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" transtypes "github.com/stacklok/toolhive/pkg/transport/types" ) diff --git a/cmd/thv/app/run_flags.go b/cmd/thv/app/run_flags.go index 37683d7b8..a74e72c6a 100644 --- a/cmd/thv/app/run_flags.go +++ b/cmd/thv/app/run_flags.go @@ -20,7 +20,7 @@ import ( "github.com/stacklok/toolhive/pkg/logger" "github.com/stacklok/toolhive/pkg/networking" "github.com/stacklok/toolhive/pkg/process" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner" "github.com/stacklok/toolhive/pkg/runner/retriever" "github.com/stacklok/toolhive/pkg/telemetry" diff --git a/cmd/thv/app/search.go b/cmd/thv/app/search.go index 928b3fc40..539a4540e 100644 --- a/cmd/thv/app/search.go +++ b/cmd/thv/app/search.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/cobra" "github.com/stacklok/toolhive/pkg/registry" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) var searchCmd = &cobra.Command{ diff --git a/docs/server/docs.go b/docs/server/docs.go index fbe679ab2..0c90e5cf1 100644 --- a/docs/server/docs.go +++ b/docs/server/docs.go @@ -6,7 +6,7 @@ import "github.com/swaggo/swag/v2" const docTemplate = `{ "schemes": {{ marshal .Schemes }}, - "components": {"schemas":{"audit.Config":{"description":"AuditConfig contains the audit logging configuration","properties":{"component":{"description":"Component is the component name to use in audit events","type":"string"},"event_types":{"description":"EventTypes specifies which event types to audit. If empty, all events are audited.","items":{"type":"string"},"type":"array","uniqueItems":false},"exclude_event_types":{"description":"ExcludeEventTypes specifies which event types to exclude from auditing.\nThis takes precedence over EventTypes.","items":{"type":"string"},"type":"array","uniqueItems":false},"include_request_data":{"description":"IncludeRequestData determines whether to include request data in audit logs","type":"boolean"},"include_response_data":{"description":"IncludeResponseData determines whether to include response data in audit logs","type":"boolean"},"log_file":{"description":"LogFile specifies the file path for audit logs. If empty, logs to stdout.","type":"string"},"max_data_size":{"description":"MaxDataSize limits the size of request/response data included in audit logs (in bytes)","type":"integer"}},"type":"object"},"auth.TokenValidatorConfig":{"description":"OIDCConfig contains OIDC configuration","properties":{"allowPrivateIP":{"description":"AllowPrivateIP allows JWKS/OIDC endpoints on private IP addresses","type":"boolean"},"audience":{"description":"Audience is the expected audience for the token","type":"string"},"authTokenFile":{"description":"AuthTokenFile is the path to file containing bearer token for authentication","type":"string"},"cacertPath":{"description":"CACertPath is the path to the CA certificate bundle for HTTPS requests","type":"string"},"clientID":{"description":"ClientID is the OIDC client ID","type":"string"},"clientSecret":{"description":"ClientSecret is the optional OIDC client secret for introspection","type":"string"},"insecureAllowHTTP":{"description":"InsecureAllowHTTP allows HTTP (non-HTTPS) OIDC issuers for development/testing\nWARNING: This is insecure and should NEVER be used in production","type":"boolean"},"introspectionURL":{"description":"IntrospectionURL is the optional introspection endpoint for validating tokens","type":"string"},"issuer":{"description":"Issuer is the OIDC issuer URL (e.g., https://accounts.google.com)","type":"string"},"jwksurl":{"description":"JWKSURL is the URL to fetch the JWKS from","type":"string"},"resourceURL":{"description":"ResourceURL is the explicit resource URL for OAuth discovery (RFC 9728)","type":"string"}},"type":"object"},"authz.CedarConfig":{"description":"Cedar is the Cedar-specific configuration.\nThis is only used when Type is ConfigTypeCedarV1.","properties":{"entities_json":{"description":"EntitiesJSON is the JSON string representing Cedar entities","type":"string"},"policies":{"description":"Policies is a list of Cedar policy strings","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"authz.Config":{"description":"AuthzConfig contains the authorization configuration","properties":{"cedar":{"$ref":"#/components/schemas/authz.CedarConfig"},"type":{"$ref":"#/components/schemas/authz.ConfigType"},"version":{"description":"Version is the version of the configuration format.","type":"string"}},"type":"object"},"authz.ConfigType":{"description":"Type is the type of authorization configuration.","type":"string","x-enum-varnames":["ConfigTypeCedarV1"]},"client.MCPClient":{"type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"client.MCPClientStatus":{"properties":{"client_type":{"description":"ClientType is the type of MCP client","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"installed":{"description":"Installed indicates whether the client is installed on the system","type":"boolean"},"registered":{"description":"Registered indicates whether the client is registered in the ToolHive configuration","type":"boolean"}},"type":"object"},"client.RegisteredClient":{"properties":{"groups":{"items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"$ref":"#/components/schemas/client.MCPClient"}},"type":"object"},"core.Workload":{"properties":{"created_at":{"description":"CreatedAt is the timestamp when the workload was created.","type":"string"},"group":{"description":"Group is the name of the group this workload belongs to, if any.","type":"string"},"labels":{"additionalProperties":{"type":"string"},"description":"Labels are the container labels (excluding standard ToolHive labels)","type":"object"},"name":{"description":"Name is the name of the workload.\nIt is used as a unique identifier.","type":"string"},"package":{"description":"Package specifies the Workload Package used to create this Workload.","type":"string"},"port":{"description":"Port is the port on which the workload is exposed.\nThis is embedded in the URL.","type":"integer"},"proxy_mode":{"description":"ProxyMode is the proxy mode that clients should use to connect.\nFor stdio transports, this will be the proxy mode (sse or streamable-http).\nFor direct transports (sse/streamable-http), this will be the same as TransportType.","type":"string"},"remote":{"description":"Remote indicates whether this is a remote workload (true) or a container workload (false).","type":"boolean"},"status":{"$ref":"#/components/schemas/runtime.WorkloadStatus"},"status_context":{"description":"StatusContext provides additional context about the workload's status.\nThe exact meaning is determined by the status and the underlying runtime.","type":"string"},"tool_type":{"description":"ToolType is the type of tool this workload represents.\nFor now, it will always be \"mcp\" - representing an MCP server.","type":"string"},"tools":{"description":"ToolsFilter is the filter on tools applied to the workload.","items":{"type":"string"},"type":"array","uniqueItems":false},"transport_type":{"$ref":"#/components/schemas/types.TransportType"},"url":{"description":"URL is the URL of the workload exposed by the ToolHive proxy.","type":"string"}},"type":"object"},"groups.Group":{"properties":{"name":{"type":"string"},"registered_clients":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"ignore.Config":{"description":"IgnoreConfig contains configuration for ignore processing","properties":{"loadGlobal":{"description":"Whether to load global ignore patterns","type":"boolean"},"printOverlays":{"description":"Whether to print resolved overlay paths for debugging","type":"boolean"}},"type":"object"},"permissions.InboundNetworkPermissions":{"description":"Inbound defines inbound network permissions","properties":{"allow_host":{"description":"AllowHost is a list of allowed hosts for inbound connections","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"permissions.NetworkPermissions":{"description":"Network defines network permissions","properties":{"inbound":{"$ref":"#/components/schemas/permissions.InboundNetworkPermissions"},"mode":{"description":"Mode specifies the network mode for the container (e.g., \"host\", \"bridge\", \"none\")\nWhen empty, the default container runtime network mode is used","type":"string"},"outbound":{"$ref":"#/components/schemas/permissions.OutboundNetworkPermissions"}},"type":"object"},"permissions.OutboundNetworkPermissions":{"description":"Outbound defines outbound network permissions","properties":{"allow_host":{"description":"AllowHost is a list of allowed hosts","items":{"type":"string"},"type":"array","uniqueItems":false},"allow_port":{"description":"AllowPort is a list of allowed ports","items":{"type":"integer"},"type":"array","uniqueItems":false},"insecure_allow_all":{"description":"InsecureAllowAll allows all outbound network connections","type":"boolean"}},"type":"object"},"permissions.Profile":{"description":"PermissionProfile is the permission profile to use","properties":{"name":{"description":"Name is the name of the profile","type":"string"},"network":{"$ref":"#/components/schemas/permissions.NetworkPermissions"},"privileged":{"description":"Privileged indicates whether the container should run in privileged mode\nWhen true, the container has access to all host devices and capabilities\nUse with extreme caution as this removes most security isolation","type":"boolean"},"read":{"description":"Read is a list of mount declarations that the container can read from\nThese can be in the following formats:\n- A single path: The same path will be mounted from host to container\n- host-path:container-path: Different paths for host and container\n- resource-uri:container-path: Mount a resource identified by URI to a container path","items":{"type":"string"},"type":"array","uniqueItems":false},"write":{"description":"Write is a list of mount declarations that the container can write to\nThese follow the same format as Read mounts but with write permissions","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"remote.Config":{"description":"RemoteAuthConfig contains OAuth configuration for remote MCP servers","properties":{"authorize_url":{"type":"string"},"callback_port":{"type":"integer"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"client_secret_file":{"type":"string"},"env_vars":{"description":"Environment variables for the client","items":{"$ref":"#/components/schemas/types.EnvVar"},"type":"array","uniqueItems":false},"headers":{"description":"Headers for HTTP requests","items":{"$ref":"#/components/schemas/types.Header"},"type":"array","uniqueItems":false},"issuer":{"description":"OAuth endpoint configuration (from registry)","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"OAuth parameters for server-specific customization","type":"object"},"resource":{"description":"Resource is the OAuth 2.0 resource indicator (RFC 8707).","type":"string"},"scopes":{"items":{"type":"string"},"type":"array","uniqueItems":false},"skip_browser":{"type":"boolean"},"timeout":{"example":"5m","type":"string"},"token_url":{"type":"string"},"use_pkce":{"type":"boolean"}},"type":"object"},"runner.RunConfig":{"properties":{"audit_config":{"$ref":"#/components/schemas/audit.Config"},"audit_config_path":{"description":"AuditConfigPath is the path to the audit configuration file","type":"string"},"authz_config":{"$ref":"#/components/schemas/authz.Config"},"authz_config_path":{"description":"AuthzConfigPath is the path to the authorization configuration file","type":"string"},"base_name":{"description":"BaseName is the base name used for the container (without prefixes)","type":"string"},"cmd_args":{"description":"CmdArgs are the arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"container_labels":{"additionalProperties":{"type":"string"},"description":"ContainerLabels are the labels to apply to the container","type":"object"},"container_name":{"description":"ContainerName is the name of the container","type":"string"},"debug":{"description":"Debug indicates whether debug mode is enabled","type":"boolean"},"env_file_dir":{"description":"EnvFileDir is the directory path to load environment files from","type":"string"},"env_vars":{"additionalProperties":{"type":"string"},"description":"EnvVars are the parsed environment variables as key-value pairs","type":"object"},"group":{"description":"Group is the name of the group this workload belongs to, if any","type":"string"},"host":{"description":"Host is the host for the HTTP proxy","type":"string"},"ignore_config":{"$ref":"#/components/schemas/ignore.Config"},"image":{"description":"Image is the Docker image to run","type":"string"},"isolate_network":{"description":"IsolateNetwork indicates whether to isolate the network for the container","type":"boolean"},"jwks_auth_token_file":{"description":"JWKSAuthTokenFile is the path to file containing auth token for JWKS/OIDC requests","type":"string"},"k8s_pod_template_patch":{"description":"K8sPodTemplatePatch is a JSON string to patch the Kubernetes pod template\nOnly applicable when using Kubernetes runtime","type":"string"},"middleware_configs":{"description":"MiddlewareConfigs contains the list of middleware to apply to the transport\nand the configuration for each middleware.","items":{"$ref":"#/components/schemas/types.MiddlewareConfig"},"type":"array","uniqueItems":false},"name":{"description":"Name is the name of the MCP server","type":"string"},"oidc_config":{"$ref":"#/components/schemas/auth.TokenValidatorConfig"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"permission_profile_name_or_path":{"description":"PermissionProfileNameOrPath is the name or path of the permission profile","type":"string"},"port":{"description":"Port is the port for the HTTP proxy to listen on (host port)","type":"integer"},"proxy_mode":{"$ref":"#/components/schemas/types.ProxyMode"},"remote_auth_config":{"$ref":"#/components/schemas/remote.Config"},"remote_url":{"description":"RemoteURL is the URL of the remote MCP server (if running remotely)","type":"string"},"schema_version":{"description":"SchemaVersion is the version of the RunConfig schema","type":"string"},"secrets":{"description":"Secrets are the secret parameters to pass to the container\nFormat: \"\u003csecret name\u003e,target=\u003ctarget environment variable\u003e\"","items":{"type":"string"},"type":"array","uniqueItems":false},"target_host":{"description":"TargetHost is the host to forward traffic to (only applicable to SSE transport)","type":"string"},"target_port":{"description":"TargetPort is the port for the container to expose (only applicable to SSE transport)","type":"integer"},"telemetry_config":{"$ref":"#/components/schemas/telemetry.Config"},"thv_ca_bundle":{"description":"ThvCABundle is the path to the CA certificate bundle for ToolHive HTTP operations","type":"string"},"token_exchange_config":{"$ref":"#/components/schemas/tokenexchange.Config"},"tools_filter":{"description":"ToolsFilter is the list of tools to filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/runner.ToolOverride"},"description":"ToolsOverride is a map from an actual tool to its overridden name and/or description","type":"object"},"transport":{"description":"Transport is the transport mode (stdio, sse, or streamable-http)","type":"string","x-enum-varnames":["TransportTypeStdio","TransportTypeSSE","TransportTypeStreamableHTTP","TransportTypeInspector"]},"trust_proxy_headers":{"description":"TrustProxyHeaders indicates whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"volumes":{"description":"Volumes are the directory mounts to pass to the container\nFormat: \"host-path:container-path[:ro]\"","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"runner.ToolOverride":{"properties":{"description":{"description":"Description is the redefined description of the tool","type":"string"},"name":{"description":"Name is the redefined name of the tool","type":"string"}},"type":"object"},"runtime.WorkloadStatus":{"description":"Status is the current status of the workload.","type":"string","x-enum-varnames":["WorkloadStatusRunning","WorkloadStatusStopped","WorkloadStatusError","WorkloadStatusStarting","WorkloadStatusStopping","WorkloadStatusUnhealthy","WorkloadStatusRemoving","WorkloadStatusUnknown","WorkloadStatusUnauthenticated"]},"secrets.SecretParameter":{"properties":{"name":{"type":"string"},"target":{"type":"string"}},"type":"object"},"telemetry.Config":{"description":"TelemetryConfig contains the OpenTelemetry configuration","properties":{"customAttributes":{"additionalProperties":{"type":"string"},"description":"CustomAttributes contains custom resource attributes to be added to all telemetry signals.\nThese are parsed from CLI flags (--otel-custom-attributes) or environment variables\n(OTEL_RESOURCE_ATTRIBUTES) as key=value pairs.\nWe use map[string]string for proper JSON serialization instead of []attribute.KeyValue\nwhich doesn't marshal/unmarshal correctly.","type":"object"},"enablePrometheusMetricsPath":{"description":"EnablePrometheusMetricsPath controls whether to expose Prometheus-style /metrics endpoint\nThe metrics are served on the main transport port at /metrics\nThis is separate from OTLP metrics which are sent to the Endpoint","type":"boolean"},"endpoint":{"description":"Endpoint is the OTLP endpoint URL","type":"string"},"environmentVariables":{"description":"EnvironmentVariables is a list of environment variable names that should be\nincluded in telemetry spans as attributes. Only variables in this list will\nbe read from the host machine and included in spans for observability.\nExample: []string{\"NODE_ENV\", \"DEPLOYMENT_ENV\", \"SERVICE_VERSION\"}","items":{"type":"string"},"type":"array","uniqueItems":false},"headers":{"additionalProperties":{"type":"string"},"description":"Headers contains authentication headers for the OTLP endpoint","type":"object"},"insecure":{"description":"Insecure indicates whether to use HTTP instead of HTTPS for the OTLP endpoint","type":"boolean"},"metricsEnabled":{"description":"MetricsEnabled controls whether OTLP metrics are enabled\nWhen false, OTLP metrics are not sent even if an endpoint is configured\nThis is independent of EnablePrometheusMetricsPath","type":"boolean"},"samplingRate":{"description":"SamplingRate is the trace sampling rate (0.0-1.0)\nOnly used when TracingEnabled is true","type":"number"},"serviceName":{"description":"ServiceName is the service name for telemetry","type":"string"},"serviceVersion":{"description":"ServiceVersion is the service version for telemetry","type":"string"},"tracingEnabled":{"description":"TracingEnabled controls whether distributed tracing is enabled\nWhen false, no tracer provider is created even if an endpoint is configured","type":"boolean"}},"type":"object"},"tokenexchange.Config":{"description":"TokenExchangeConfig contains token exchange configuration for external authentication","properties":{"audience":{"description":"Audience is the target audience for the exchanged token","type":"string"},"client_id":{"description":"ClientID is the OAuth 2.0 client identifier","type":"string"},"client_secret":{"description":"ClientSecret is the OAuth 2.0 client secret","type":"string"},"external_token_header_name":{"description":"ExternalTokenHeaderName is the name of the custom header to use when HeaderStrategy is \"custom\"","type":"string"},"header_strategy":{"description":"HeaderStrategy determines how to inject the token\nValid values: HeaderStrategyReplace (default), HeaderStrategyCustom","type":"string"},"scopes":{"description":"Scopes is the list of scopes to request for the exchanged token","items":{"type":"string"},"type":"array","uniqueItems":false},"subject_token_type":{"description":"SubjectTokenType specifies the type of the subject token being exchanged.\nCommon values: tokenTypeAccessToken (default), tokenTypeIDToken, tokenTypeJWT.\nIf empty, defaults to tokenTypeAccessToken.","type":"string"},"token_url":{"description":"TokenURL is the OAuth 2.0 token endpoint URL","type":"string"}},"type":"object"},"types.EnvVar":{"properties":{"default":{"description":"Default is the value to use if the environment variable is not explicitly provided\nOnly used for non-required variables","type":"string"},"description":{"description":"Description is a human-readable explanation of the variable's purpose","type":"string"},"name":{"description":"Name is the environment variable name (e.g., API_KEY)","type":"string"},"required":{"description":"Required indicates whether this environment variable must be provided\nIf true and not provided via command line or secrets, the user will be prompted for a value","type":"boolean"},"secret":{"description":"Secret indicates whether this environment variable contains sensitive information\nIf true, the value will be stored as a secret rather than as a plain environment variable","type":"boolean"}},"type":"object"},"types.Group":{"properties":{"description":{"description":"Description is a human-readable description of the group's purpose and functionality","type":"string"},"name":{"description":"Name is the identifier for the group, used when referencing the group in commands","type":"string"},"remote_servers":{"additionalProperties":{"$ref":"#/components/schemas/types.RemoteServerMetadata"},"description":"RemoteServers is a map of server names to their corresponding remote server definitions within this group","type":"object"},"servers":{"additionalProperties":{"$ref":"#/components/schemas/types.ImageMetadata"},"description":"Servers is a map of server names to their corresponding server definitions within this group","type":"object"}},"type":"object"},"types.Header":{"properties":{"choices":{"description":"Choices provides a list of valid values for the header (optional)","items":{"type":"string"},"type":"array","uniqueItems":false},"default":{"description":"Default is the value to use if the header is not explicitly provided\nOnly used for non-required headers","type":"string"},"description":{"description":"Description is a human-readable explanation of the header's purpose","type":"string"},"name":{"description":"Name is the header name (e.g., X-API-Key, Authorization)","type":"string"},"required":{"description":"Required indicates whether this header must be provided\nIf true and not provided via command line or secrets, the user will be prompted for a value","type":"boolean"},"secret":{"description":"Secret indicates whether this header contains sensitive information\nIf true, the value will be stored as a secret rather than as plain text","type":"boolean"}},"type":"object"},"types.ImageMetadata":{"description":"Container server details (if it's a container server)","properties":{"args":{"description":"Args are the default command-line arguments to pass to the MCP server container.\nThese arguments will be used only if no command-line arguments are provided by the user.\nIf the user provides arguments, they will override these defaults.","items":{"type":"string"},"type":"array","uniqueItems":false},"custom_metadata":{"additionalProperties":{},"description":"CustomMetadata allows for additional user-defined metadata","type":"object"},"description":{"description":"Description is a human-readable description of the server's purpose and functionality","type":"string"},"docker_tags":{"description":"DockerTags lists the available Docker tags for this server image","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"description":"EnvVars defines environment variables that can be passed to the server","items":{"$ref":"#/components/schemas/types.EnvVar"},"type":"array","uniqueItems":false},"image":{"description":"Image is the Docker image reference for the MCP server","type":"string"},"metadata":{"$ref":"#/components/schemas/types.Metadata"},"name":{"description":"Name is the identifier for the MCP server, used when referencing the server in commands\nIf not provided, it will be auto-generated from the registry key","type":"string"},"permissions":{"$ref":"#/components/schemas/permissions.Profile"},"provenance":{"$ref":"#/components/schemas/types.Provenance"},"repository_url":{"description":"RepositoryURL is the URL to the source code repository for the server","type":"string"},"status":{"description":"Status indicates whether the server is currently active or deprecated","type":"string"},"tags":{"description":"Tags are categorization labels for the server to aid in discovery and filtering","items":{"type":"string"},"type":"array","uniqueItems":false},"target_port":{"description":"TargetPort is the port for the container to expose (only applicable to SSE and Streamable HTTP transports)","type":"integer"},"tier":{"description":"Tier represents the tier classification level of the server, e.g., \"Official\" or \"Community\"","type":"string"},"tools":{"description":"Tools is a list of tool names provided by this MCP server","items":{"type":"string"},"type":"array","uniqueItems":false},"transport":{"description":"Transport defines the communication protocol for the server\nFor containers: stdio, sse, or streamable-http\nFor remote servers: sse or streamable-http (stdio not supported)","type":"string"}},"type":"object"},"types.Metadata":{"description":"Metadata contains additional information about the server such as popularity metrics","properties":{"last_updated":{"description":"LastUpdated is the timestamp when the server was last updated, in RFC3339 format","type":"string"},"pulls":{"description":"Pulls indicates how many times the server image has been downloaded","type":"integer"},"stars":{"description":"Stars represents the popularity rating or number of stars for the server","type":"integer"}},"type":"object"},"types.MiddlewareConfig":{"properties":{"parameters":{"description":"Parameters is a JSON object containing the middleware parameters.\nIt is stored as a raw message to allow flexible parameter types.","type":"object"},"type":{"description":"Type is a string representing the middleware type.","type":"string"}},"type":"object"},"types.OAuthConfig":{"description":"OAuthConfig provides OAuth/OIDC configuration for authentication to the remote server\nUsed with the thv proxy command's --remote-auth flags","properties":{"authorize_url":{"description":"AuthorizeURL is the OAuth authorization endpoint URL\nUsed for non-OIDC OAuth flows when issuer is not provided","type":"string"},"callback_port":{"description":"CallbackPort is the specific port to use for the OAuth callback server\nIf not specified, a random available port will be used","type":"integer"},"client_id":{"description":"ClientID is the OAuth client ID for authentication","type":"string"},"issuer":{"description":"Issuer is the OAuth/OIDC issuer URL (e.g., https://accounts.google.com)\nUsed for OIDC discovery to find authorization and token endpoints","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"OAuthParams contains additional OAuth parameters to include in the authorization request\nThese are server-specific parameters like \"prompt\", \"response_mode\", etc.","type":"object"},"resource":{"description":"Resource is the OAuth 2.0 resource indicator (RFC 8707)","type":"string"},"scopes":{"description":"Scopes are the OAuth scopes to request\nIf not specified, defaults to [\"openid\", \"profile\", \"email\"] for OIDC","items":{"type":"string"},"type":"array","uniqueItems":false},"token_url":{"description":"TokenURL is the OAuth token endpoint URL\nUsed for non-OIDC OAuth flows when issuer is not provided","type":"string"},"use_pkce":{"description":"UsePKCE indicates whether to use PKCE for the OAuth flow\nDefaults to true for enhanced security","type":"boolean"}},"type":"object"},"types.Provenance":{"description":"Provenance contains verification and signing metadata","properties":{"attestation":{"$ref":"#/components/schemas/types.VerifiedAttestation"},"cert_issuer":{"type":"string"},"repository_ref":{"type":"string"},"repository_uri":{"type":"string"},"runner_environment":{"type":"string"},"signer_identity":{"type":"string"},"sigstore_url":{"type":"string"}},"type":"object"},"types.ProxyMode":{"description":"ProxyMode is the proxy mode for stdio transport (\"sse\" or \"streamable-http\")","type":"string","x-enum-varnames":["ProxyModeSSE","ProxyModeStreamableHTTP"]},"types.Registry":{"description":"Full registry data","properties":{"groups":{"description":"Groups is a slice of group definitions containing related MCP servers","items":{"$ref":"#/components/schemas/types.Group"},"type":"array","uniqueItems":false},"last_updated":{"description":"LastUpdated is the timestamp when the registry was last updated, in RFC3339 format","type":"string"},"remote_servers":{"additionalProperties":{"$ref":"#/components/schemas/types.RemoteServerMetadata"},"description":"RemoteServers is a map of server names to their corresponding remote server definitions\nThese are MCP servers accessed via HTTP/HTTPS using the thv proxy command","type":"object"},"servers":{"additionalProperties":{"$ref":"#/components/schemas/types.ImageMetadata"},"description":"Servers is a map of server names to their corresponding server definitions","type":"object"},"version":{"description":"Version is the schema version of the registry","type":"string"}},"type":"object"},"types.RemoteServerMetadata":{"description":"Remote server details (if it's a remote server)","properties":{"custom_metadata":{"additionalProperties":{},"description":"CustomMetadata allows for additional user-defined metadata","type":"object"},"description":{"description":"Description is a human-readable description of the server's purpose and functionality","type":"string"},"env_vars":{"description":"EnvVars defines environment variables that can be passed to configure the client\nThese might be needed for client-side configuration when connecting to the remote server","items":{"$ref":"#/components/schemas/types.EnvVar"},"type":"array","uniqueItems":false},"headers":{"description":"Headers defines HTTP headers that can be passed to the remote server for authentication\nThese are used with the thv proxy command's authentication features","items":{"$ref":"#/components/schemas/types.Header"},"type":"array","uniqueItems":false},"metadata":{"$ref":"#/components/schemas/types.Metadata"},"name":{"description":"Name is the identifier for the MCP server, used when referencing the server in commands\nIf not provided, it will be auto-generated from the registry key","type":"string"},"oauth_config":{"$ref":"#/components/schemas/types.OAuthConfig"},"repository_url":{"description":"RepositoryURL is the URL to the source code repository for the server","type":"string"},"status":{"description":"Status indicates whether the server is currently active or deprecated","type":"string"},"tags":{"description":"Tags are categorization labels for the server to aid in discovery and filtering","items":{"type":"string"},"type":"array","uniqueItems":false},"tier":{"description":"Tier represents the tier classification level of the server, e.g., \"Official\" or \"Community\"","type":"string"},"tools":{"description":"Tools is a list of tool names provided by this MCP server","items":{"type":"string"},"type":"array","uniqueItems":false},"transport":{"description":"Transport defines the communication protocol for the server\nFor containers: stdio, sse, or streamable-http\nFor remote servers: sse or streamable-http (stdio not supported)","type":"string"},"url":{"description":"URL is the endpoint URL for the remote MCP server (e.g., https://api.example.com/mcp)","type":"string"}},"type":"object"},"types.TransportType":{"description":"TransportType is the type of transport used for this workload.","type":"string","x-enum-varnames":["TransportTypeStdio","TransportTypeSSE","TransportTypeStreamableHTTP","TransportTypeInspector"]},"types.VerifiedAttestation":{"properties":{"predicate":{},"predicate_type":{"type":"string"}},"type":"object"},"v1.RegistryType":{"description":"Type of registry (file, url, or default)","type":"string","x-enum-varnames":["RegistryTypeFile","RegistryTypeURL","RegistryTypeAPI","RegistryTypeDefault"]},"v1.UpdateRegistryRequest":{"description":"Request containing registry configuration updates","properties":{"allow_private_ip":{"description":"Allow private IP addresses for registry URL or API URL","type":"boolean"},"api_url":{"description":"MCP Registry API URL","type":"string"},"local_path":{"description":"Local registry file path","type":"string"},"url":{"description":"Registry URL (for remote registries)","type":"string"}},"type":"object"},"v1.UpdateRegistryResponse":{"description":"Response containing update result","properties":{"message":{"description":"Status message","type":"string"},"type":{"description":"Registry type after update","type":"string"}},"type":"object"},"v1.bulkClientRequest":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"names":{"description":"Names is the list of client names to operate on.","items":{"type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"type":"array","uniqueItems":false}},"type":"object"},"v1.bulkOperationRequest":{"properties":{"group":{"description":"Group name to operate on (mutually exclusive with names)","type":"string"},"names":{"description":"Names of the workloads to operate on","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.clientStatusResponse":{"properties":{"clients":{"items":{"$ref":"#/components/schemas/client.MCPClientStatus"},"type":"array","uniqueItems":false}},"type":"object"},"v1.createClientRequest":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"description":"Name is the type of the client to register.","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]}},"type":"object"},"v1.createClientResponse":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"description":"Name is the type of the client that was registered.","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]}},"type":"object"},"v1.createGroupRequest":{"properties":{"name":{"description":"Name of the group to create","type":"string"}},"type":"object"},"v1.createGroupResponse":{"properties":{"name":{"description":"Name of the created group","type":"string"}},"type":"object"},"v1.createRequest":{"description":"Request to create a new workload","properties":{"authz_config":{"description":"Authorization configuration","type":"string"},"cmd_arguments":{"description":"Command arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"additionalProperties":{"type":"string"},"description":"Environment variables to set in the container","type":"object"},"group":{"description":"Group name this workload belongs to","type":"string"},"headers":{"items":{"$ref":"#/components/schemas/types.Header"},"type":"array","uniqueItems":false},"host":{"description":"Host to bind to","type":"string"},"image":{"description":"Docker image to use","type":"string"},"name":{"description":"Name of the workload","type":"string"},"network_isolation":{"description":"Whether network isolation is turned on. This applies the rules in the permission profile.","type":"boolean"},"oauth_config":{"$ref":"#/components/schemas/v1.remoteOAuthConfig"},"oidc":{"$ref":"#/components/schemas/v1.oidcOptions"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"proxy_mode":{"description":"Proxy mode to use","type":"string"},"proxy_port":{"description":"Port for the HTTP proxy to listen on","type":"integer"},"secrets":{"description":"Secret parameters to inject","items":{"$ref":"#/components/schemas/secrets.SecretParameter"},"type":"array","uniqueItems":false},"target_port":{"description":"Port to expose from the container","type":"integer"},"tools":{"description":"Tools filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/v1.toolOverride"},"description":"Tools override","type":"object"},"transport":{"description":"Transport configuration","type":"string"},"trust_proxy_headers":{"description":"Whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"url":{"description":"Remote server specific fields","type":"string"},"volumes":{"description":"Volume mounts","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.createSecretRequest":{"description":"Request to create a new secret","properties":{"key":{"description":"Secret key name","type":"string"},"value":{"description":"Secret value","type":"string"}},"type":"object"},"v1.createSecretResponse":{"description":"Response after creating a secret","properties":{"key":{"description":"Secret key that was created","type":"string"},"message":{"description":"Success message","type":"string"}},"type":"object"},"v1.createWorkloadResponse":{"description":"Response after successfully creating a workload","properties":{"name":{"description":"Name of the created workload","type":"string"},"port":{"description":"Port the workload is listening on","type":"integer"}},"type":"object"},"v1.getRegistryResponse":{"description":"Response containing registry details","properties":{"last_updated":{"description":"Last updated timestamp","type":"string"},"name":{"description":"Name of the registry","type":"string"},"registry":{"$ref":"#/components/schemas/types.Registry"},"server_count":{"description":"Number of servers in the registry","type":"integer"},"source":{"description":"Source of the registry (URL, file path, or empty string for built-in)","type":"string"},"type":{"description":"Type of registry (file, url, or default)","type":"string","x-enum-varnames":["RegistryTypeFile","RegistryTypeURL","RegistryTypeAPI","RegistryTypeDefault"]},"version":{"description":"Version of the registry schema","type":"string"}},"type":"object"},"v1.getSecretsProviderResponse":{"description":"Response containing secrets provider details","properties":{"capabilities":{"$ref":"#/components/schemas/v1.providerCapabilitiesResponse"},"name":{"description":"Name of the secrets provider","type":"string"},"provider_type":{"description":"Type of the secrets provider","type":"string"}},"type":"object"},"v1.getServerResponse":{"description":"Response containing server details","properties":{"is_remote":{"description":"Indicates if this is a remote server","type":"boolean"},"remote_server":{"$ref":"#/components/schemas/types.RemoteServerMetadata"},"server":{"$ref":"#/components/schemas/types.ImageMetadata"}},"type":"object"},"v1.groupListResponse":{"properties":{"groups":{"description":"List of groups","items":{"$ref":"#/components/schemas/groups.Group"},"type":"array","uniqueItems":false}},"type":"object"},"v1.listSecretsResponse":{"description":"Response containing a list of secret keys","properties":{"keys":{"description":"List of secret keys","items":{"$ref":"#/components/schemas/v1.secretKeyResponse"},"type":"array","uniqueItems":false}},"type":"object"},"v1.listServersResponse":{"description":"Response containing a list of servers","properties":{"remote_servers":{"description":"List of remote servers in the registry (if any)","items":{"$ref":"#/components/schemas/types.RemoteServerMetadata"},"type":"array","uniqueItems":false},"servers":{"description":"List of container servers in the registry","items":{"$ref":"#/components/schemas/types.ImageMetadata"},"type":"array","uniqueItems":false}},"type":"object"},"v1.oidcOptions":{"description":"OIDC configuration options","properties":{"audience":{"description":"Expected audience","type":"string"},"client_id":{"description":"OAuth2 client ID","type":"string"},"client_secret":{"description":"OAuth2 client secret","type":"string"},"introspection_url":{"description":"Token introspection URL for OIDC","type":"string"},"issuer":{"description":"OIDC issuer URL","type":"string"},"jwks_url":{"description":"JWKS URL for key verification","type":"string"}},"type":"object"},"v1.providerCapabilitiesResponse":{"description":"Capabilities of the secrets provider","properties":{"can_cleanup":{"description":"Whether the provider can cleanup all secrets","type":"boolean"},"can_delete":{"description":"Whether the provider can delete secrets","type":"boolean"},"can_list":{"description":"Whether the provider can list secrets","type":"boolean"},"can_read":{"description":"Whether the provider can read secrets","type":"boolean"},"can_write":{"description":"Whether the provider can write secrets","type":"boolean"}},"type":"object"},"v1.registryInfo":{"description":"Basic information about a registry","properties":{"last_updated":{"description":"Last updated timestamp","type":"string"},"name":{"description":"Name of the registry","type":"string"},"server_count":{"description":"Number of servers in the registry","type":"integer"},"source":{"description":"Source of the registry (URL, file path, or empty string for built-in)","type":"string"},"type":{"$ref":"#/components/schemas/v1.RegistryType"},"version":{"description":"Version of the registry schema","type":"string"}},"type":"object"},"v1.registryListResponse":{"description":"Response containing a list of registries","properties":{"registries":{"description":"List of registries","items":{"$ref":"#/components/schemas/v1.registryInfo"},"type":"array","uniqueItems":false}},"type":"object"},"v1.remoteOAuthConfig":{"description":"OAuth configuration for remote server authentication","properties":{"authorize_url":{"description":"OAuth authorization endpoint URL (alternative to issuer for non-OIDC OAuth)","type":"string"},"callback_port":{"description":"Specific port for OAuth callback server","type":"integer"},"client_id":{"description":"OAuth client ID for authentication","type":"string"},"client_secret":{"$ref":"#/components/schemas/secrets.SecretParameter"},"issuer":{"description":"OAuth/OIDC issuer URL (e.g., https://accounts.google.com)","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"Additional OAuth parameters for server-specific customization","type":"object"},"resource":{"description":"OAuth 2.0 resource indicator (RFC 8707)","type":"string"},"scopes":{"description":"OAuth scopes to request","items":{"type":"string"},"type":"array","uniqueItems":false},"skip_browser":{"description":"Whether to skip opening browser for OAuth flow (defaults to false)","type":"boolean"},"token_url":{"description":"OAuth token endpoint URL (alternative to issuer for non-OIDC OAuth)","type":"string"},"use_pkce":{"description":"Whether to use PKCE for the OAuth flow","type":"boolean"}},"type":"object"},"v1.secretKeyResponse":{"description":"Secret key information","properties":{"description":{"description":"Optional description of the secret","type":"string"},"key":{"description":"Secret key name","type":"string"}},"type":"object"},"v1.setupSecretsRequest":{"description":"Request to setup a secrets provider","properties":{"password":{"description":"Password for encrypted provider (optional, can be set via environment variable)\nTODO Review environment variable for this","type":"string"},"provider_type":{"description":"Type of the secrets provider (encrypted, 1password, none)","type":"string"}},"type":"object"},"v1.setupSecretsResponse":{"description":"Response after initializing a secrets provider","properties":{"message":{"description":"Success message","type":"string"},"provider_type":{"description":"Type of the secrets provider that was setup","type":"string"}},"type":"object"},"v1.toolOverride":{"description":"Tool override","properties":{"description":{"description":"Description of the tool","type":"string"},"name":{"description":"Name of the tool","type":"string"}},"type":"object"},"v1.updateRequest":{"description":"Request to update an existing workload (name cannot be changed)","properties":{"authz_config":{"description":"Authorization configuration","type":"string"},"cmd_arguments":{"description":"Command arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"additionalProperties":{"type":"string"},"description":"Environment variables to set in the container","type":"object"},"group":{"description":"Group name this workload belongs to","type":"string"},"headers":{"items":{"$ref":"#/components/schemas/types.Header"},"type":"array","uniqueItems":false},"host":{"description":"Host to bind to","type":"string"},"image":{"description":"Docker image to use","type":"string"},"network_isolation":{"description":"Whether network isolation is turned on. This applies the rules in the permission profile.","type":"boolean"},"oauth_config":{"$ref":"#/components/schemas/v1.remoteOAuthConfig"},"oidc":{"$ref":"#/components/schemas/v1.oidcOptions"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"proxy_mode":{"description":"Proxy mode to use","type":"string"},"proxy_port":{"description":"Port for the HTTP proxy to listen on","type":"integer"},"secrets":{"description":"Secret parameters to inject","items":{"$ref":"#/components/schemas/secrets.SecretParameter"},"type":"array","uniqueItems":false},"target_port":{"description":"Port to expose from the container","type":"integer"},"tools":{"description":"Tools filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/v1.toolOverride"},"description":"Tools override","type":"object"},"transport":{"description":"Transport configuration","type":"string"},"trust_proxy_headers":{"description":"Whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"url":{"description":"Remote server specific fields","type":"string"},"volumes":{"description":"Volume mounts","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.updateSecretRequest":{"description":"Request to update an existing secret","properties":{"value":{"description":"New secret value","type":"string"}},"type":"object"},"v1.updateSecretResponse":{"description":"Response after updating a secret","properties":{"key":{"description":"Secret key that was updated","type":"string"},"message":{"description":"Success message","type":"string"}},"type":"object"},"v1.versionResponse":{"properties":{"version":{"type":"string"}},"type":"object"},"v1.workloadListResponse":{"description":"Response containing a list of workloads","properties":{"workloads":{"description":"List of container information for each workload","items":{"$ref":"#/components/schemas/core.Workload"},"type":"array","uniqueItems":false}},"type":"object"},"v1.workloadStatusResponse":{"description":"Response containing workload status information","properties":{"status":{"description":"Current status of the workload","type":"string","x-enum-varnames":["WorkloadStatusRunning","WorkloadStatusStopped","WorkloadStatusError","WorkloadStatusStarting","WorkloadStatusStopping","WorkloadStatusUnhealthy","WorkloadStatusRemoving","WorkloadStatusUnknown","WorkloadStatusUnauthenticated"]}},"type":"object"}}}, + "components": {"schemas":{"audit.Config":{"description":"AuditConfig contains the audit logging configuration","properties":{"component":{"description":"Component is the component name to use in audit events","type":"string"},"event_types":{"description":"EventTypes specifies which event types to audit. If empty, all events are audited.","items":{"type":"string"},"type":"array","uniqueItems":false},"exclude_event_types":{"description":"ExcludeEventTypes specifies which event types to exclude from auditing.\nThis takes precedence over EventTypes.","items":{"type":"string"},"type":"array","uniqueItems":false},"include_request_data":{"description":"IncludeRequestData determines whether to include request data in audit logs","type":"boolean"},"include_response_data":{"description":"IncludeResponseData determines whether to include response data in audit logs","type":"boolean"},"log_file":{"description":"LogFile specifies the file path for audit logs. If empty, logs to stdout.","type":"string"},"max_data_size":{"description":"MaxDataSize limits the size of request/response data included in audit logs (in bytes)","type":"integer"}},"type":"object"},"auth.TokenValidatorConfig":{"description":"OIDCConfig contains OIDC configuration","properties":{"allowPrivateIP":{"description":"AllowPrivateIP allows JWKS/OIDC endpoints on private IP addresses","type":"boolean"},"audience":{"description":"Audience is the expected audience for the token","type":"string"},"authTokenFile":{"description":"AuthTokenFile is the path to file containing bearer token for authentication","type":"string"},"cacertPath":{"description":"CACertPath is the path to the CA certificate bundle for HTTPS requests","type":"string"},"clientID":{"description":"ClientID is the OIDC client ID","type":"string"},"clientSecret":{"description":"ClientSecret is the optional OIDC client secret for introspection","type":"string"},"insecureAllowHTTP":{"description":"InsecureAllowHTTP allows HTTP (non-HTTPS) OIDC issuers for development/testing\nWARNING: This is insecure and should NEVER be used in production","type":"boolean"},"introspectionURL":{"description":"IntrospectionURL is the optional introspection endpoint for validating tokens","type":"string"},"issuer":{"description":"Issuer is the OIDC issuer URL (e.g., https://accounts.google.com)","type":"string"},"jwksurl":{"description":"JWKSURL is the URL to fetch the JWKS from","type":"string"},"resourceURL":{"description":"ResourceURL is the explicit resource URL for OAuth discovery (RFC 9728)","type":"string"}},"type":"object"},"authz.CedarConfig":{"description":"Cedar is the Cedar-specific configuration.\nThis is only used when Type is ConfigTypeCedarV1.","properties":{"entities_json":{"description":"EntitiesJSON is the JSON string representing Cedar entities","type":"string"},"policies":{"description":"Policies is a list of Cedar policy strings","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"authz.Config":{"description":"AuthzConfig contains the authorization configuration","properties":{"cedar":{"$ref":"#/components/schemas/authz.CedarConfig"},"type":{"$ref":"#/components/schemas/authz.ConfigType"},"version":{"description":"Version is the version of the configuration format.","type":"string"}},"type":"object"},"authz.ConfigType":{"description":"Type is the type of authorization configuration.","type":"string","x-enum-varnames":["ConfigTypeCedarV1"]},"client.MCPClient":{"type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"client.MCPClientStatus":{"properties":{"client_type":{"description":"ClientType is the type of MCP client","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"installed":{"description":"Installed indicates whether the client is installed on the system","type":"boolean"},"registered":{"description":"Registered indicates whether the client is registered in the ToolHive configuration","type":"boolean"}},"type":"object"},"client.RegisteredClient":{"properties":{"groups":{"items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"$ref":"#/components/schemas/client.MCPClient"}},"type":"object"},"core.Workload":{"properties":{"created_at":{"description":"CreatedAt is the timestamp when the workload was created.","type":"string"},"group":{"description":"Group is the name of the group this workload belongs to, if any.","type":"string"},"labels":{"additionalProperties":{"type":"string"},"description":"Labels are the container labels (excluding standard ToolHive labels)","type":"object"},"name":{"description":"Name is the name of the workload.\nIt is used as a unique identifier.","type":"string"},"package":{"description":"Package specifies the Workload Package used to create this Workload.","type":"string"},"port":{"description":"Port is the port on which the workload is exposed.\nThis is embedded in the URL.","type":"integer"},"proxy_mode":{"description":"ProxyMode is the proxy mode that clients should use to connect.\nFor stdio transports, this will be the proxy mode (sse or streamable-http).\nFor direct transports (sse/streamable-http), this will be the same as TransportType.","type":"string"},"remote":{"description":"Remote indicates whether this is a remote workload (true) or a container workload (false).","type":"boolean"},"status":{"$ref":"#/components/schemas/runtime.WorkloadStatus"},"status_context":{"description":"StatusContext provides additional context about the workload's status.\nThe exact meaning is determined by the status and the underlying runtime.","type":"string"},"tool_type":{"description":"ToolType is the type of tool this workload represents.\nFor now, it will always be \"mcp\" - representing an MCP server.","type":"string"},"tools":{"description":"ToolsFilter is the filter on tools applied to the workload.","items":{"type":"string"},"type":"array","uniqueItems":false},"transport_type":{"$ref":"#/components/schemas/types.TransportType"},"url":{"description":"URL is the URL of the workload exposed by the ToolHive proxy.","type":"string"}},"type":"object"},"groups.Group":{"properties":{"name":{"type":"string"},"registered_clients":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"ignore.Config":{"description":"IgnoreConfig contains configuration for ignore processing","properties":{"loadGlobal":{"description":"Whether to load global ignore patterns","type":"boolean"},"printOverlays":{"description":"Whether to print resolved overlay paths for debugging","type":"boolean"}},"type":"object"},"permissions.InboundNetworkPermissions":{"description":"Inbound defines inbound network permissions","properties":{"allow_host":{"description":"AllowHost is a list of allowed hosts for inbound connections","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"permissions.NetworkPermissions":{"description":"Network defines network permissions","properties":{"inbound":{"$ref":"#/components/schemas/permissions.InboundNetworkPermissions"},"mode":{"description":"Mode specifies the network mode for the container (e.g., \"host\", \"bridge\", \"none\")\nWhen empty, the default container runtime network mode is used","type":"string"},"outbound":{"$ref":"#/components/schemas/permissions.OutboundNetworkPermissions"}},"type":"object"},"permissions.OutboundNetworkPermissions":{"description":"Outbound defines outbound network permissions","properties":{"allow_host":{"description":"AllowHost is a list of allowed hosts","items":{"type":"string"},"type":"array","uniqueItems":false},"allow_port":{"description":"AllowPort is a list of allowed ports","items":{"type":"integer"},"type":"array","uniqueItems":false},"insecure_allow_all":{"description":"InsecureAllowAll allows all outbound network connections","type":"boolean"}},"type":"object"},"permissions.Profile":{"description":"PermissionProfile is the permission profile to use","properties":{"name":{"description":"Name is the name of the profile","type":"string"},"network":{"$ref":"#/components/schemas/permissions.NetworkPermissions"},"privileged":{"description":"Privileged indicates whether the container should run in privileged mode\nWhen true, the container has access to all host devices and capabilities\nUse with extreme caution as this removes most security isolation","type":"boolean"},"read":{"description":"Read is a list of mount declarations that the container can read from\nThese can be in the following formats:\n- A single path: The same path will be mounted from host to container\n- host-path:container-path: Different paths for host and container\n- resource-uri:container-path: Mount a resource identified by URI to a container path","items":{"type":"string"},"type":"array","uniqueItems":false},"write":{"description":"Write is a list of mount declarations that the container can write to\nThese follow the same format as Read mounts but with write permissions","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"registry.EnvVar":{"properties":{"default":{"description":"Default is the value to use if the environment variable is not explicitly provided\nOnly used for non-required variables","type":"string"},"description":{"description":"Description is a human-readable explanation of the variable's purpose","type":"string"},"name":{"description":"Name is the environment variable name (e.g., API_KEY)","type":"string"},"required":{"description":"Required indicates whether this environment variable must be provided\nIf true and not provided via command line or secrets, the user will be prompted for a value","type":"boolean"},"secret":{"description":"Secret indicates whether this environment variable contains sensitive information\nIf true, the value will be stored as a secret rather than as a plain environment variable","type":"boolean"}},"type":"object"},"registry.Group":{"properties":{"description":{"description":"Description is a human-readable description of the group's purpose and functionality","type":"string"},"name":{"description":"Name is the identifier for the group, used when referencing the group in commands","type":"string"},"remote_servers":{"additionalProperties":{"$ref":"#/components/schemas/registry.RemoteServerMetadata"},"description":"RemoteServers is a map of server names to their corresponding remote server definitions within this group","type":"object"},"servers":{"additionalProperties":{"$ref":"#/components/schemas/registry.ImageMetadata"},"description":"Servers is a map of server names to their corresponding server definitions within this group","type":"object"}},"type":"object"},"registry.Header":{"properties":{"choices":{"description":"Choices provides a list of valid values for the header (optional)","items":{"type":"string"},"type":"array","uniqueItems":false},"default":{"description":"Default is the value to use if the header is not explicitly provided\nOnly used for non-required headers","type":"string"},"description":{"description":"Description is a human-readable explanation of the header's purpose","type":"string"},"name":{"description":"Name is the header name (e.g., X-API-Key, Authorization)","type":"string"},"required":{"description":"Required indicates whether this header must be provided\nIf true and not provided via command line or secrets, the user will be prompted for a value","type":"boolean"},"secret":{"description":"Secret indicates whether this header contains sensitive information\nIf true, the value will be stored as a secret rather than as plain text","type":"boolean"}},"type":"object"},"registry.ImageMetadata":{"description":"Container server details (if it's a container server)","properties":{"args":{"description":"Args are the default command-line arguments to pass to the MCP server container.\nThese arguments will be used only if no command-line arguments are provided by the user.\nIf the user provides arguments, they will override these defaults.","items":{"type":"string"},"type":"array","uniqueItems":false},"custom_metadata":{"additionalProperties":{},"description":"CustomMetadata allows for additional user-defined metadata","type":"object"},"description":{"description":"Description is a human-readable description of the server's purpose and functionality","type":"string"},"docker_tags":{"description":"DockerTags lists the available Docker tags for this server image","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"description":"EnvVars defines environment variables that can be passed to the server","items":{"$ref":"#/components/schemas/registry.EnvVar"},"type":"array","uniqueItems":false},"image":{"description":"Image is the Docker image reference for the MCP server","type":"string"},"metadata":{"$ref":"#/components/schemas/registry.Metadata"},"name":{"description":"Name is the identifier for the MCP server, used when referencing the server in commands\nIf not provided, it will be auto-generated from the registry key","type":"string"},"permissions":{"$ref":"#/components/schemas/permissions.Profile"},"provenance":{"$ref":"#/components/schemas/registry.Provenance"},"repository_url":{"description":"RepositoryURL is the URL to the source code repository for the server","type":"string"},"status":{"description":"Status indicates whether the server is currently active or deprecated","type":"string"},"tags":{"description":"Tags are categorization labels for the server to aid in discovery and filtering","items":{"type":"string"},"type":"array","uniqueItems":false},"target_port":{"description":"TargetPort is the port for the container to expose (only applicable to SSE and Streamable HTTP transports)","type":"integer"},"tier":{"description":"Tier represents the tier classification level of the server, e.g., \"Official\" or \"Community\"","type":"string"},"tools":{"description":"Tools is a list of tool names provided by this MCP server","items":{"type":"string"},"type":"array","uniqueItems":false},"transport":{"description":"Transport defines the communication protocol for the server\nFor containers: stdio, sse, or streamable-http\nFor remote servers: sse or streamable-http (stdio not supported)","type":"string"}},"type":"object"},"registry.Metadata":{"description":"Metadata contains additional information about the server such as popularity metrics","properties":{"last_updated":{"description":"LastUpdated is the timestamp when the server was last updated, in RFC3339 format","type":"string"},"pulls":{"description":"Pulls indicates how many times the server image has been downloaded","type":"integer"},"stars":{"description":"Stars represents the popularity rating or number of stars for the server","type":"integer"}},"type":"object"},"registry.OAuthConfig":{"description":"OAuthConfig provides OAuth/OIDC configuration for authentication to the remote server\nUsed with the thv proxy command's --remote-auth flags","properties":{"authorize_url":{"description":"AuthorizeURL is the OAuth authorization endpoint URL\nUsed for non-OIDC OAuth flows when issuer is not provided","type":"string"},"callback_port":{"description":"CallbackPort is the specific port to use for the OAuth callback server\nIf not specified, a random available port will be used","type":"integer"},"client_id":{"description":"ClientID is the OAuth client ID for authentication","type":"string"},"issuer":{"description":"Issuer is the OAuth/OIDC issuer URL (e.g., https://accounts.google.com)\nUsed for OIDC discovery to find authorization and token endpoints","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"OAuthParams contains additional OAuth parameters to include in the authorization request\nThese are server-specific parameters like \"prompt\", \"response_mode\", etc.","type":"object"},"resource":{"description":"Resource is the OAuth 2.0 resource indicator (RFC 8707)","type":"string"},"scopes":{"description":"Scopes are the OAuth scopes to request\nIf not specified, defaults to [\"openid\", \"profile\", \"email\"] for OIDC","items":{"type":"string"},"type":"array","uniqueItems":false},"token_url":{"description":"TokenURL is the OAuth token endpoint URL\nUsed for non-OIDC OAuth flows when issuer is not provided","type":"string"},"use_pkce":{"description":"UsePKCE indicates whether to use PKCE for the OAuth flow\nDefaults to true for enhanced security","type":"boolean"}},"type":"object"},"registry.Provenance":{"description":"Provenance contains verification and signing metadata","properties":{"attestation":{"$ref":"#/components/schemas/registry.VerifiedAttestation"},"cert_issuer":{"type":"string"},"repository_ref":{"type":"string"},"repository_uri":{"type":"string"},"runner_environment":{"type":"string"},"signer_identity":{"type":"string"},"sigstore_url":{"type":"string"}},"type":"object"},"registry.Registry":{"description":"Full registry data","properties":{"groups":{"description":"Groups is a slice of group definitions containing related MCP servers","items":{"$ref":"#/components/schemas/registry.Group"},"type":"array","uniqueItems":false},"last_updated":{"description":"LastUpdated is the timestamp when the registry was last updated, in RFC3339 format","type":"string"},"remote_servers":{"additionalProperties":{"$ref":"#/components/schemas/registry.RemoteServerMetadata"},"description":"RemoteServers is a map of server names to their corresponding remote server definitions\nThese are MCP servers accessed via HTTP/HTTPS using the thv proxy command","type":"object"},"servers":{"additionalProperties":{"$ref":"#/components/schemas/registry.ImageMetadata"},"description":"Servers is a map of server names to their corresponding server definitions","type":"object"},"version":{"description":"Version is the schema version of the registry","type":"string"}},"type":"object"},"registry.RemoteServerMetadata":{"description":"Remote server details (if it's a remote server)","properties":{"custom_metadata":{"additionalProperties":{},"description":"CustomMetadata allows for additional user-defined metadata","type":"object"},"description":{"description":"Description is a human-readable description of the server's purpose and functionality","type":"string"},"env_vars":{"description":"EnvVars defines environment variables that can be passed to configure the client\nThese might be needed for client-side configuration when connecting to the remote server","items":{"$ref":"#/components/schemas/registry.EnvVar"},"type":"array","uniqueItems":false},"headers":{"description":"Headers defines HTTP headers that can be passed to the remote server for authentication\nThese are used with the thv proxy command's authentication features","items":{"$ref":"#/components/schemas/registry.Header"},"type":"array","uniqueItems":false},"metadata":{"$ref":"#/components/schemas/registry.Metadata"},"name":{"description":"Name is the identifier for the MCP server, used when referencing the server in commands\nIf not provided, it will be auto-generated from the registry key","type":"string"},"oauth_config":{"$ref":"#/components/schemas/registry.OAuthConfig"},"repository_url":{"description":"RepositoryURL is the URL to the source code repository for the server","type":"string"},"status":{"description":"Status indicates whether the server is currently active or deprecated","type":"string"},"tags":{"description":"Tags are categorization labels for the server to aid in discovery and filtering","items":{"type":"string"},"type":"array","uniqueItems":false},"tier":{"description":"Tier represents the tier classification level of the server, e.g., \"Official\" or \"Community\"","type":"string"},"tools":{"description":"Tools is a list of tool names provided by this MCP server","items":{"type":"string"},"type":"array","uniqueItems":false},"transport":{"description":"Transport defines the communication protocol for the server\nFor containers: stdio, sse, or streamable-http\nFor remote servers: sse or streamable-http (stdio not supported)","type":"string"},"url":{"description":"URL is the endpoint URL for the remote MCP server (e.g., https://api.example.com/mcp)","type":"string"}},"type":"object"},"registry.VerifiedAttestation":{"properties":{"predicate":{},"predicate_type":{"type":"string"}},"type":"object"},"remote.Config":{"description":"RemoteAuthConfig contains OAuth configuration for remote MCP servers","properties":{"authorize_url":{"type":"string"},"callback_port":{"type":"integer"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"client_secret_file":{"type":"string"},"env_vars":{"description":"Environment variables for the client","items":{"$ref":"#/components/schemas/registry.EnvVar"},"type":"array","uniqueItems":false},"headers":{"description":"Headers for HTTP requests","items":{"$ref":"#/components/schemas/registry.Header"},"type":"array","uniqueItems":false},"issuer":{"description":"OAuth endpoint configuration (from registry)","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"OAuth parameters for server-specific customization","type":"object"},"resource":{"description":"Resource is the OAuth 2.0 resource indicator (RFC 8707).","type":"string"},"scopes":{"items":{"type":"string"},"type":"array","uniqueItems":false},"skip_browser":{"type":"boolean"},"timeout":{"example":"5m","type":"string"},"token_url":{"type":"string"},"use_pkce":{"type":"boolean"}},"type":"object"},"runner.RunConfig":{"properties":{"audit_config":{"$ref":"#/components/schemas/audit.Config"},"audit_config_path":{"description":"AuditConfigPath is the path to the audit configuration file","type":"string"},"authz_config":{"$ref":"#/components/schemas/authz.Config"},"authz_config_path":{"description":"AuthzConfigPath is the path to the authorization configuration file","type":"string"},"base_name":{"description":"BaseName is the base name used for the container (without prefixes)","type":"string"},"cmd_args":{"description":"CmdArgs are the arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"container_labels":{"additionalProperties":{"type":"string"},"description":"ContainerLabels are the labels to apply to the container","type":"object"},"container_name":{"description":"ContainerName is the name of the container","type":"string"},"debug":{"description":"Debug indicates whether debug mode is enabled","type":"boolean"},"env_file_dir":{"description":"EnvFileDir is the directory path to load environment files from","type":"string"},"env_vars":{"additionalProperties":{"type":"string"},"description":"EnvVars are the parsed environment variables as key-value pairs","type":"object"},"group":{"description":"Group is the name of the group this workload belongs to, if any","type":"string"},"host":{"description":"Host is the host for the HTTP proxy","type":"string"},"ignore_config":{"$ref":"#/components/schemas/ignore.Config"},"image":{"description":"Image is the Docker image to run","type":"string"},"isolate_network":{"description":"IsolateNetwork indicates whether to isolate the network for the container","type":"boolean"},"jwks_auth_token_file":{"description":"JWKSAuthTokenFile is the path to file containing auth token for JWKS/OIDC requests","type":"string"},"k8s_pod_template_patch":{"description":"K8sPodTemplatePatch is a JSON string to patch the Kubernetes pod template\nOnly applicable when using Kubernetes runtime","type":"string"},"middleware_configs":{"description":"MiddlewareConfigs contains the list of middleware to apply to the transport\nand the configuration for each middleware.","items":{"$ref":"#/components/schemas/types.MiddlewareConfig"},"type":"array","uniqueItems":false},"name":{"description":"Name is the name of the MCP server","type":"string"},"oidc_config":{"$ref":"#/components/schemas/auth.TokenValidatorConfig"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"permission_profile_name_or_path":{"description":"PermissionProfileNameOrPath is the name or path of the permission profile","type":"string"},"port":{"description":"Port is the port for the HTTP proxy to listen on (host port)","type":"integer"},"proxy_mode":{"$ref":"#/components/schemas/types.ProxyMode"},"remote_auth_config":{"$ref":"#/components/schemas/remote.Config"},"remote_url":{"description":"RemoteURL is the URL of the remote MCP server (if running remotely)","type":"string"},"schema_version":{"description":"SchemaVersion is the version of the RunConfig schema","type":"string"},"secrets":{"description":"Secrets are the secret parameters to pass to the container\nFormat: \"\u003csecret name\u003e,target=\u003ctarget environment variable\u003e\"","items":{"type":"string"},"type":"array","uniqueItems":false},"target_host":{"description":"TargetHost is the host to forward traffic to (only applicable to SSE transport)","type":"string"},"target_port":{"description":"TargetPort is the port for the container to expose (only applicable to SSE transport)","type":"integer"},"telemetry_config":{"$ref":"#/components/schemas/telemetry.Config"},"thv_ca_bundle":{"description":"ThvCABundle is the path to the CA certificate bundle for ToolHive HTTP operations","type":"string"},"token_exchange_config":{"$ref":"#/components/schemas/tokenexchange.Config"},"tools_filter":{"description":"ToolsFilter is the list of tools to filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/runner.ToolOverride"},"description":"ToolsOverride is a map from an actual tool to its overridden name and/or description","type":"object"},"transport":{"description":"Transport is the transport mode (stdio, sse, or streamable-http)","type":"string","x-enum-varnames":["TransportTypeStdio","TransportTypeSSE","TransportTypeStreamableHTTP","TransportTypeInspector"]},"trust_proxy_headers":{"description":"TrustProxyHeaders indicates whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"volumes":{"description":"Volumes are the directory mounts to pass to the container\nFormat: \"host-path:container-path[:ro]\"","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"runner.ToolOverride":{"properties":{"description":{"description":"Description is the redefined description of the tool","type":"string"},"name":{"description":"Name is the redefined name of the tool","type":"string"}},"type":"object"},"runtime.WorkloadStatus":{"description":"Status is the current status of the workload.","type":"string","x-enum-varnames":["WorkloadStatusRunning","WorkloadStatusStopped","WorkloadStatusError","WorkloadStatusStarting","WorkloadStatusStopping","WorkloadStatusUnhealthy","WorkloadStatusRemoving","WorkloadStatusUnknown","WorkloadStatusUnauthenticated"]},"secrets.SecretParameter":{"properties":{"name":{"type":"string"},"target":{"type":"string"}},"type":"object"},"telemetry.Config":{"description":"TelemetryConfig contains the OpenTelemetry configuration","properties":{"customAttributes":{"additionalProperties":{"type":"string"},"description":"CustomAttributes contains custom resource attributes to be added to all telemetry signals.\nThese are parsed from CLI flags (--otel-custom-attributes) or environment variables\n(OTEL_RESOURCE_ATTRIBUTES) as key=value pairs.\nWe use map[string]string for proper JSON serialization instead of []attribute.KeyValue\nwhich doesn't marshal/unmarshal correctly.","type":"object"},"enablePrometheusMetricsPath":{"description":"EnablePrometheusMetricsPath controls whether to expose Prometheus-style /metrics endpoint\nThe metrics are served on the main transport port at /metrics\nThis is separate from OTLP metrics which are sent to the Endpoint","type":"boolean"},"endpoint":{"description":"Endpoint is the OTLP endpoint URL","type":"string"},"environmentVariables":{"description":"EnvironmentVariables is a list of environment variable names that should be\nincluded in telemetry spans as attributes. Only variables in this list will\nbe read from the host machine and included in spans for observability.\nExample: []string{\"NODE_ENV\", \"DEPLOYMENT_ENV\", \"SERVICE_VERSION\"}","items":{"type":"string"},"type":"array","uniqueItems":false},"headers":{"additionalProperties":{"type":"string"},"description":"Headers contains authentication headers for the OTLP endpoint","type":"object"},"insecure":{"description":"Insecure indicates whether to use HTTP instead of HTTPS for the OTLP endpoint","type":"boolean"},"metricsEnabled":{"description":"MetricsEnabled controls whether OTLP metrics are enabled\nWhen false, OTLP metrics are not sent even if an endpoint is configured\nThis is independent of EnablePrometheusMetricsPath","type":"boolean"},"samplingRate":{"description":"SamplingRate is the trace sampling rate (0.0-1.0)\nOnly used when TracingEnabled is true","type":"number"},"serviceName":{"description":"ServiceName is the service name for telemetry","type":"string"},"serviceVersion":{"description":"ServiceVersion is the service version for telemetry","type":"string"},"tracingEnabled":{"description":"TracingEnabled controls whether distributed tracing is enabled\nWhen false, no tracer provider is created even if an endpoint is configured","type":"boolean"}},"type":"object"},"tokenexchange.Config":{"description":"TokenExchangeConfig contains token exchange configuration for external authentication","properties":{"audience":{"description":"Audience is the target audience for the exchanged token","type":"string"},"client_id":{"description":"ClientID is the OAuth 2.0 client identifier","type":"string"},"client_secret":{"description":"ClientSecret is the OAuth 2.0 client secret","type":"string"},"external_token_header_name":{"description":"ExternalTokenHeaderName is the name of the custom header to use when HeaderStrategy is \"custom\"","type":"string"},"header_strategy":{"description":"HeaderStrategy determines how to inject the token\nValid values: HeaderStrategyReplace (default), HeaderStrategyCustom","type":"string"},"scopes":{"description":"Scopes is the list of scopes to request for the exchanged token","items":{"type":"string"},"type":"array","uniqueItems":false},"subject_token_type":{"description":"SubjectTokenType specifies the type of the subject token being exchanged.\nCommon values: tokenTypeAccessToken (default), tokenTypeIDToken, tokenTypeJWT.\nIf empty, defaults to tokenTypeAccessToken.","type":"string"},"token_url":{"description":"TokenURL is the OAuth 2.0 token endpoint URL","type":"string"}},"type":"object"},"types.MiddlewareConfig":{"properties":{"parameters":{"description":"Parameters is a JSON object containing the middleware parameters.\nIt is stored as a raw message to allow flexible parameter types.","type":"object"},"type":{"description":"Type is a string representing the middleware type.","type":"string"}},"type":"object"},"types.ProxyMode":{"description":"ProxyMode is the proxy mode for stdio transport (\"sse\" or \"streamable-http\")","type":"string","x-enum-varnames":["ProxyModeSSE","ProxyModeStreamableHTTP"]},"types.TransportType":{"description":"TransportType is the type of transport used for this workload.","type":"string","x-enum-varnames":["TransportTypeStdio","TransportTypeSSE","TransportTypeStreamableHTTP","TransportTypeInspector"]},"v1.RegistryType":{"description":"Type of registry (file, url, or default)","type":"string","x-enum-varnames":["RegistryTypeFile","RegistryTypeURL","RegistryTypeAPI","RegistryTypeDefault"]},"v1.UpdateRegistryRequest":{"description":"Request containing registry configuration updates","properties":{"allow_private_ip":{"description":"Allow private IP addresses for registry URL or API URL","type":"boolean"},"api_url":{"description":"MCP Registry API URL","type":"string"},"local_path":{"description":"Local registry file path","type":"string"},"url":{"description":"Registry URL (for remote registries)","type":"string"}},"type":"object"},"v1.UpdateRegistryResponse":{"description":"Response containing update result","properties":{"message":{"description":"Status message","type":"string"},"type":{"description":"Registry type after update","type":"string"}},"type":"object"},"v1.bulkClientRequest":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"names":{"description":"Names is the list of client names to operate on.","items":{"type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"type":"array","uniqueItems":false}},"type":"object"},"v1.bulkOperationRequest":{"properties":{"group":{"description":"Group name to operate on (mutually exclusive with names)","type":"string"},"names":{"description":"Names of the workloads to operate on","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.clientStatusResponse":{"properties":{"clients":{"items":{"$ref":"#/components/schemas/client.MCPClientStatus"},"type":"array","uniqueItems":false}},"type":"object"},"v1.createClientRequest":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"description":"Name is the type of the client to register.","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]}},"type":"object"},"v1.createClientResponse":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"description":"Name is the type of the client that was registered.","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]}},"type":"object"},"v1.createGroupRequest":{"properties":{"name":{"description":"Name of the group to create","type":"string"}},"type":"object"},"v1.createGroupResponse":{"properties":{"name":{"description":"Name of the created group","type":"string"}},"type":"object"},"v1.createRequest":{"description":"Request to create a new workload","properties":{"authz_config":{"description":"Authorization configuration","type":"string"},"cmd_arguments":{"description":"Command arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"additionalProperties":{"type":"string"},"description":"Environment variables to set in the container","type":"object"},"group":{"description":"Group name this workload belongs to","type":"string"},"headers":{"items":{"$ref":"#/components/schemas/registry.Header"},"type":"array","uniqueItems":false},"host":{"description":"Host to bind to","type":"string"},"image":{"description":"Docker image to use","type":"string"},"name":{"description":"Name of the workload","type":"string"},"network_isolation":{"description":"Whether network isolation is turned on. This applies the rules in the permission profile.","type":"boolean"},"oauth_config":{"$ref":"#/components/schemas/v1.remoteOAuthConfig"},"oidc":{"$ref":"#/components/schemas/v1.oidcOptions"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"proxy_mode":{"description":"Proxy mode to use","type":"string"},"proxy_port":{"description":"Port for the HTTP proxy to listen on","type":"integer"},"secrets":{"description":"Secret parameters to inject","items":{"$ref":"#/components/schemas/secrets.SecretParameter"},"type":"array","uniqueItems":false},"target_port":{"description":"Port to expose from the container","type":"integer"},"tools":{"description":"Tools filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/v1.toolOverride"},"description":"Tools override","type":"object"},"transport":{"description":"Transport configuration","type":"string"},"trust_proxy_headers":{"description":"Whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"url":{"description":"Remote server specific fields","type":"string"},"volumes":{"description":"Volume mounts","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.createSecretRequest":{"description":"Request to create a new secret","properties":{"key":{"description":"Secret key name","type":"string"},"value":{"description":"Secret value","type":"string"}},"type":"object"},"v1.createSecretResponse":{"description":"Response after creating a secret","properties":{"key":{"description":"Secret key that was created","type":"string"},"message":{"description":"Success message","type":"string"}},"type":"object"},"v1.createWorkloadResponse":{"description":"Response after successfully creating a workload","properties":{"name":{"description":"Name of the created workload","type":"string"},"port":{"description":"Port the workload is listening on","type":"integer"}},"type":"object"},"v1.getRegistryResponse":{"description":"Response containing registry details","properties":{"last_updated":{"description":"Last updated timestamp","type":"string"},"name":{"description":"Name of the registry","type":"string"},"registry":{"$ref":"#/components/schemas/registry.Registry"},"server_count":{"description":"Number of servers in the registry","type":"integer"},"source":{"description":"Source of the registry (URL, file path, or empty string for built-in)","type":"string"},"type":{"description":"Type of registry (file, url, or default)","type":"string","x-enum-varnames":["RegistryTypeFile","RegistryTypeURL","RegistryTypeAPI","RegistryTypeDefault"]},"version":{"description":"Version of the registry schema","type":"string"}},"type":"object"},"v1.getSecretsProviderResponse":{"description":"Response containing secrets provider details","properties":{"capabilities":{"$ref":"#/components/schemas/v1.providerCapabilitiesResponse"},"name":{"description":"Name of the secrets provider","type":"string"},"provider_type":{"description":"Type of the secrets provider","type":"string"}},"type":"object"},"v1.getServerResponse":{"description":"Response containing server details","properties":{"is_remote":{"description":"Indicates if this is a remote server","type":"boolean"},"remote_server":{"$ref":"#/components/schemas/registry.RemoteServerMetadata"},"server":{"$ref":"#/components/schemas/registry.ImageMetadata"}},"type":"object"},"v1.groupListResponse":{"properties":{"groups":{"description":"List of groups","items":{"$ref":"#/components/schemas/groups.Group"},"type":"array","uniqueItems":false}},"type":"object"},"v1.listSecretsResponse":{"description":"Response containing a list of secret keys","properties":{"keys":{"description":"List of secret keys","items":{"$ref":"#/components/schemas/v1.secretKeyResponse"},"type":"array","uniqueItems":false}},"type":"object"},"v1.listServersResponse":{"description":"Response containing a list of servers","properties":{"remote_servers":{"description":"List of remote servers in the registry (if any)","items":{"$ref":"#/components/schemas/registry.RemoteServerMetadata"},"type":"array","uniqueItems":false},"servers":{"description":"List of container servers in the registry","items":{"$ref":"#/components/schemas/registry.ImageMetadata"},"type":"array","uniqueItems":false}},"type":"object"},"v1.oidcOptions":{"description":"OIDC configuration options","properties":{"audience":{"description":"Expected audience","type":"string"},"client_id":{"description":"OAuth2 client ID","type":"string"},"client_secret":{"description":"OAuth2 client secret","type":"string"},"introspection_url":{"description":"Token introspection URL for OIDC","type":"string"},"issuer":{"description":"OIDC issuer URL","type":"string"},"jwks_url":{"description":"JWKS URL for key verification","type":"string"}},"type":"object"},"v1.providerCapabilitiesResponse":{"description":"Capabilities of the secrets provider","properties":{"can_cleanup":{"description":"Whether the provider can cleanup all secrets","type":"boolean"},"can_delete":{"description":"Whether the provider can delete secrets","type":"boolean"},"can_list":{"description":"Whether the provider can list secrets","type":"boolean"},"can_read":{"description":"Whether the provider can read secrets","type":"boolean"},"can_write":{"description":"Whether the provider can write secrets","type":"boolean"}},"type":"object"},"v1.registryInfo":{"description":"Basic information about a registry","properties":{"last_updated":{"description":"Last updated timestamp","type":"string"},"name":{"description":"Name of the registry","type":"string"},"server_count":{"description":"Number of servers in the registry","type":"integer"},"source":{"description":"Source of the registry (URL, file path, or empty string for built-in)","type":"string"},"type":{"$ref":"#/components/schemas/v1.RegistryType"},"version":{"description":"Version of the registry schema","type":"string"}},"type":"object"},"v1.registryListResponse":{"description":"Response containing a list of registries","properties":{"registries":{"description":"List of registries","items":{"$ref":"#/components/schemas/v1.registryInfo"},"type":"array","uniqueItems":false}},"type":"object"},"v1.remoteOAuthConfig":{"description":"OAuth configuration for remote server authentication","properties":{"authorize_url":{"description":"OAuth authorization endpoint URL (alternative to issuer for non-OIDC OAuth)","type":"string"},"callback_port":{"description":"Specific port for OAuth callback server","type":"integer"},"client_id":{"description":"OAuth client ID for authentication","type":"string"},"client_secret":{"$ref":"#/components/schemas/secrets.SecretParameter"},"issuer":{"description":"OAuth/OIDC issuer URL (e.g., https://accounts.google.com)","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"Additional OAuth parameters for server-specific customization","type":"object"},"resource":{"description":"OAuth 2.0 resource indicator (RFC 8707)","type":"string"},"scopes":{"description":"OAuth scopes to request","items":{"type":"string"},"type":"array","uniqueItems":false},"skip_browser":{"description":"Whether to skip opening browser for OAuth flow (defaults to false)","type":"boolean"},"token_url":{"description":"OAuth token endpoint URL (alternative to issuer for non-OIDC OAuth)","type":"string"},"use_pkce":{"description":"Whether to use PKCE for the OAuth flow","type":"boolean"}},"type":"object"},"v1.secretKeyResponse":{"description":"Secret key information","properties":{"description":{"description":"Optional description of the secret","type":"string"},"key":{"description":"Secret key name","type":"string"}},"type":"object"},"v1.setupSecretsRequest":{"description":"Request to setup a secrets provider","properties":{"password":{"description":"Password for encrypted provider (optional, can be set via environment variable)\nTODO Review environment variable for this","type":"string"},"provider_type":{"description":"Type of the secrets provider (encrypted, 1password, none)","type":"string"}},"type":"object"},"v1.setupSecretsResponse":{"description":"Response after initializing a secrets provider","properties":{"message":{"description":"Success message","type":"string"},"provider_type":{"description":"Type of the secrets provider that was setup","type":"string"}},"type":"object"},"v1.toolOverride":{"description":"Tool override","properties":{"description":{"description":"Description of the tool","type":"string"},"name":{"description":"Name of the tool","type":"string"}},"type":"object"},"v1.updateRequest":{"description":"Request to update an existing workload (name cannot be changed)","properties":{"authz_config":{"description":"Authorization configuration","type":"string"},"cmd_arguments":{"description":"Command arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"additionalProperties":{"type":"string"},"description":"Environment variables to set in the container","type":"object"},"group":{"description":"Group name this workload belongs to","type":"string"},"headers":{"items":{"$ref":"#/components/schemas/registry.Header"},"type":"array","uniqueItems":false},"host":{"description":"Host to bind to","type":"string"},"image":{"description":"Docker image to use","type":"string"},"network_isolation":{"description":"Whether network isolation is turned on. This applies the rules in the permission profile.","type":"boolean"},"oauth_config":{"$ref":"#/components/schemas/v1.remoteOAuthConfig"},"oidc":{"$ref":"#/components/schemas/v1.oidcOptions"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"proxy_mode":{"description":"Proxy mode to use","type":"string"},"proxy_port":{"description":"Port for the HTTP proxy to listen on","type":"integer"},"secrets":{"description":"Secret parameters to inject","items":{"$ref":"#/components/schemas/secrets.SecretParameter"},"type":"array","uniqueItems":false},"target_port":{"description":"Port to expose from the container","type":"integer"},"tools":{"description":"Tools filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/v1.toolOverride"},"description":"Tools override","type":"object"},"transport":{"description":"Transport configuration","type":"string"},"trust_proxy_headers":{"description":"Whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"url":{"description":"Remote server specific fields","type":"string"},"volumes":{"description":"Volume mounts","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.updateSecretRequest":{"description":"Request to update an existing secret","properties":{"value":{"description":"New secret value","type":"string"}},"type":"object"},"v1.updateSecretResponse":{"description":"Response after updating a secret","properties":{"key":{"description":"Secret key that was updated","type":"string"},"message":{"description":"Success message","type":"string"}},"type":"object"},"v1.versionResponse":{"properties":{"version":{"type":"string"}},"type":"object"},"v1.workloadListResponse":{"description":"Response containing a list of workloads","properties":{"workloads":{"description":"List of container information for each workload","items":{"$ref":"#/components/schemas/core.Workload"},"type":"array","uniqueItems":false}},"type":"object"},"v1.workloadStatusResponse":{"description":"Response containing workload status information","properties":{"status":{"description":"Current status of the workload","type":"string","x-enum-varnames":["WorkloadStatusRunning","WorkloadStatusStopped","WorkloadStatusError","WorkloadStatusStarting","WorkloadStatusStopping","WorkloadStatusUnhealthy","WorkloadStatusRemoving","WorkloadStatusUnknown","WorkloadStatusUnauthenticated"]}},"type":"object"}}}, "info": {"description":"{{escape .Description}}","title":"{{.Title}}","version":"{{.Version}}"}, "externalDocs": {"description":"","url":""}, "paths": {"/api/openapi.json":{"get":{"description":"Returns the OpenAPI specification for the API","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"OpenAPI specification"}},"summary":"Get OpenAPI specification","tags":["system"]}},"/api/v1beta/clients":{"get":{"description":"List all registered clients in ToolHive","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/client.RegisteredClient"},"type":"array"}}},"description":"OK"}},"summary":"List all clients","tags":["clients"]},"post":{"description":"Register a new client with ToolHive","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createClientRequest"}}},"description":"Client to register","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createClientResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"}},"summary":"Register a new client","tags":["clients"]}},"/api/v1beta/clients/register":{"post":{"description":"Register multiple clients with ToolHive","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkClientRequest"}}},"description":"Clients to register","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/v1.createClientResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"}},"summary":"Register multiple clients","tags":["clients"]}},"/api/v1beta/clients/unregister":{"post":{"description":"Unregister multiple clients from ToolHive","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkClientRequest"}}},"description":"Clients to unregister","required":true},"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"}},"summary":"Unregister multiple clients","tags":["clients"]}},"/api/v1beta/clients/{name}":{"delete":{"description":"Unregister a client from ToolHive","parameters":[{"description":"Client name to unregister","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"}},"summary":"Unregister a client","tags":["clients"]}},"/api/v1beta/clients/{name}/groups/{group}":{"delete":{"description":"Unregister a client from a specific group in ToolHive","parameters":[{"description":"Client name to unregister","in":"path","name":"name","required":true,"schema":{"type":"string"}},{"description":"Group name to remove client from","in":"path","name":"group","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Client or group not found"}},"summary":"Unregister a client from a specific group","tags":["clients"]}},"/api/v1beta/discovery/clients":{"get":{"description":"List all clients compatible with ToolHive and their status","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.clientStatusResponse"}}},"description":"OK"}},"summary":"List all clients status","tags":["discovery"]}},"/api/v1beta/groups":{"get":{"description":"Get a list of all groups","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.groupListResponse"}}},"description":"OK"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"List all groups","tags":["groups"]},"post":{"description":"Create a new group with the specified name","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createGroupRequest"}}},"description":"Group creation request","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createGroupResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"409":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Conflict"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Create a new group","tags":["groups"]}},"/api/v1beta/groups/{name}":{"delete":{"description":"Delete a group by name.","parameters":[{"description":"Group name","in":"path","name":"name","required":true,"schema":{"type":"string"}},{"description":"Delete all workloads in the group (default: false, moves workloads to default group)","in":"query","name":"with-workloads","schema":{"type":"boolean"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Delete a group","tags":["groups"]},"get":{"description":"Get details of a specific group","parameters":[{"description":"Group name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/groups.Group"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Get group details","tags":["groups"]}},"/api/v1beta/registry":{"get":{"description":"Get a list of the current registries","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.registryListResponse"}}},"description":"OK"}},"summary":"List registries","tags":["registry"]},"post":{"description":"Add a new registry","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"501":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Implemented"}},"summary":"Add a registry","tags":["registry"]}},"/api/v1beta/registry/{name}":{"delete":{"description":"Remove a specific registry","parameters":[{"description":"Registry name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Remove a registry","tags":["registry"]},"get":{"description":"Get details of a specific registry","parameters":[{"description":"Registry name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.getRegistryResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get a registry","tags":["registry"]},"put":{"description":"Update registry URL or local path for the default registry","parameters":[{"description":"Registry name (must be 'default')","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.UpdateRegistryRequest"}}},"description":"Registry configuration","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.UpdateRegistryResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Update registry configuration","tags":["registry"]}},"/api/v1beta/registry/{name}/servers":{"get":{"description":"Get a list of servers in a specific registry","parameters":[{"description":"Registry name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.listServersResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"List servers in a registry","tags":["registry"]}},"/api/v1beta/registry/{name}/servers/{serverName}":{"get":{"description":"Get details of a specific server in a registry","parameters":[{"description":"Registry name","in":"path","name":"name","required":true,"schema":{"type":"string"}},{"description":"ImageMetadata name","in":"path","name":"serverName","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.getServerResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get a server from a registry","tags":["registry"]}},"/api/v1beta/secrets":{"post":{"description":"Setup the secrets provider with the specified type and configuration.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.setupSecretsRequest"}}},"description":"Setup secrets provider request","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.setupSecretsResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Setup or reconfigure secrets provider","tags":["secrets"]}},"/api/v1beta/secrets/default":{"get":{"description":"Get details of the default secrets provider","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.getSecretsProviderResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Get secrets provider details","tags":["secrets"]}},"/api/v1beta/secrets/default/keys":{"get":{"description":"Get a list of all secret keys from the default provider","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.listSecretsResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup"},"405":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Method Not Allowed - Provider doesn't support listing"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"List secrets","tags":["secrets"]},"post":{"description":"Create a new secret in the default provider (encrypted provider only)","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createSecretRequest"}}},"description":"Create secret request","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createSecretResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup"},"405":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Method Not Allowed - Provider doesn't support writing"},"409":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Conflict - Secret already exists"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Create a new secret","tags":["secrets"]}},"/api/v1beta/secrets/default/keys/{key}":{"delete":{"description":"Delete a secret from the default provider (encrypted provider only)","parameters":[{"description":"Secret key","in":"path","name":"key","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup or secret not found"},"405":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Method Not Allowed - Provider doesn't support deletion"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Delete a secret","tags":["secrets"]},"put":{"description":"Update an existing secret in the default provider (encrypted provider only)","parameters":[{"description":"Secret key","in":"path","name":"key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.updateSecretRequest"}}},"description":"Update secret request","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.updateSecretResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup or secret not found"},"405":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Method Not Allowed - Provider doesn't support writing"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Update a secret","tags":["secrets"]}},"/api/v1beta/version":{"get":{"description":"Returns the current version of the server","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.versionResponse"}}},"description":"OK"}},"summary":"Get server version","tags":["version"]}},"/api/v1beta/workloads":{"get":{"description":"Get a list of all running workloads, optionally filtered by group","parameters":[{"description":"List all workloads, including stopped ones","in":"query","name":"all","schema":{"type":"boolean"}},{"description":"Filter workloads by group name","in":"query","name":"group","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.workloadListResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Group not found"}},"summary":"List all workloads","tags":["workloads"]},"post":{"description":"Create and start a new workload","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createRequest"}}},"description":"Create workload request","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createWorkloadResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"409":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Conflict"}},"summary":"Create a new workload","tags":["workloads"]}},"/api/v1beta/workloads/delete":{"post":{"description":"Delete multiple workloads by name or by group","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkOperationRequest"}}},"description":"Bulk delete request (names or group)","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"}},"summary":"Delete workloads in bulk","tags":["workloads"]}},"/api/v1beta/workloads/restart":{"post":{"description":"Restart multiple workloads by name or by group","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkOperationRequest"}}},"description":"Bulk restart request (names or group)","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"}},"summary":"Restart workloads in bulk","tags":["workloads"]}},"/api/v1beta/workloads/stop":{"post":{"description":"Stop multiple workloads by name or by group","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkOperationRequest"}}},"description":"Bulk stop request (names or group)","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"}},"summary":"Stop workloads in bulk","tags":["workloads"]}},"/api/v1beta/workloads/{name}":{"delete":{"description":"Delete a workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Delete a workload","tags":["workloads"]},"get":{"description":"Get details of a specific workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createRequest"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get workload details","tags":["workloads"]}},"/api/v1beta/workloads/{name}/edit":{"post":{"description":"Update an existing workload configuration","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.updateRequest"}}},"description":"Update workload request","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createWorkloadResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Update workload","tags":["workloads"]}},"/api/v1beta/workloads/{name}/export":{"get":{"description":"Export a workload's run configuration as JSON","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.RunConfig"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Export workload configuration","tags":["workloads"]}},"/api/v1beta/workloads/{name}/logs":{"get":{"description":"Retrieve at most 100 lines of logs for a specific workload by name.","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"Logs for the specified workload"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid workload name"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get logs for a specific workload","tags":["logs"]}},"/api/v1beta/workloads/{name}/proxy-logs":{"get":{"description":"Retrieve proxy logs for a specific workload by name from the file system.","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"Proxy logs for the specified workload"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid workload name"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Proxy logs not found for workload"}},"summary":"Get proxy logs for a specific workload","tags":["logs"]}},"/api/v1beta/workloads/{name}/restart":{"post":{"description":"Restart a running workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Restart a workload","tags":["workloads"]}},"/api/v1beta/workloads/{name}/status":{"get":{"description":"Get the current status of a specific workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.workloadStatusResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get workload status","tags":["workloads"]}},"/api/v1beta/workloads/{name}/stop":{"post":{"description":"Stop a running workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Stop a workload","tags":["workloads"]}},"/health":{"get":{"description":"Check if the API is healthy","responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"}},"summary":"Health check","tags":["system"]}}}, diff --git a/docs/server/swagger.json b/docs/server/swagger.json index bc3ccb491..4aa578579 100644 --- a/docs/server/swagger.json +++ b/docs/server/swagger.json @@ -1,5 +1,5 @@ { - "components": {"schemas":{"audit.Config":{"description":"AuditConfig contains the audit logging configuration","properties":{"component":{"description":"Component is the component name to use in audit events","type":"string"},"event_types":{"description":"EventTypes specifies which event types to audit. If empty, all events are audited.","items":{"type":"string"},"type":"array","uniqueItems":false},"exclude_event_types":{"description":"ExcludeEventTypes specifies which event types to exclude from auditing.\nThis takes precedence over EventTypes.","items":{"type":"string"},"type":"array","uniqueItems":false},"include_request_data":{"description":"IncludeRequestData determines whether to include request data in audit logs","type":"boolean"},"include_response_data":{"description":"IncludeResponseData determines whether to include response data in audit logs","type":"boolean"},"log_file":{"description":"LogFile specifies the file path for audit logs. If empty, logs to stdout.","type":"string"},"max_data_size":{"description":"MaxDataSize limits the size of request/response data included in audit logs (in bytes)","type":"integer"}},"type":"object"},"auth.TokenValidatorConfig":{"description":"OIDCConfig contains OIDC configuration","properties":{"allowPrivateIP":{"description":"AllowPrivateIP allows JWKS/OIDC endpoints on private IP addresses","type":"boolean"},"audience":{"description":"Audience is the expected audience for the token","type":"string"},"authTokenFile":{"description":"AuthTokenFile is the path to file containing bearer token for authentication","type":"string"},"cacertPath":{"description":"CACertPath is the path to the CA certificate bundle for HTTPS requests","type":"string"},"clientID":{"description":"ClientID is the OIDC client ID","type":"string"},"clientSecret":{"description":"ClientSecret is the optional OIDC client secret for introspection","type":"string"},"insecureAllowHTTP":{"description":"InsecureAllowHTTP allows HTTP (non-HTTPS) OIDC issuers for development/testing\nWARNING: This is insecure and should NEVER be used in production","type":"boolean"},"introspectionURL":{"description":"IntrospectionURL is the optional introspection endpoint for validating tokens","type":"string"},"issuer":{"description":"Issuer is the OIDC issuer URL (e.g., https://accounts.google.com)","type":"string"},"jwksurl":{"description":"JWKSURL is the URL to fetch the JWKS from","type":"string"},"resourceURL":{"description":"ResourceURL is the explicit resource URL for OAuth discovery (RFC 9728)","type":"string"}},"type":"object"},"authz.CedarConfig":{"description":"Cedar is the Cedar-specific configuration.\nThis is only used when Type is ConfigTypeCedarV1.","properties":{"entities_json":{"description":"EntitiesJSON is the JSON string representing Cedar entities","type":"string"},"policies":{"description":"Policies is a list of Cedar policy strings","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"authz.Config":{"description":"AuthzConfig contains the authorization configuration","properties":{"cedar":{"$ref":"#/components/schemas/authz.CedarConfig"},"type":{"$ref":"#/components/schemas/authz.ConfigType"},"version":{"description":"Version is the version of the configuration format.","type":"string"}},"type":"object"},"authz.ConfigType":{"description":"Type is the type of authorization configuration.","type":"string","x-enum-varnames":["ConfigTypeCedarV1"]},"client.MCPClient":{"type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"client.MCPClientStatus":{"properties":{"client_type":{"description":"ClientType is the type of MCP client","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"installed":{"description":"Installed indicates whether the client is installed on the system","type":"boolean"},"registered":{"description":"Registered indicates whether the client is registered in the ToolHive configuration","type":"boolean"}},"type":"object"},"client.RegisteredClient":{"properties":{"groups":{"items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"$ref":"#/components/schemas/client.MCPClient"}},"type":"object"},"core.Workload":{"properties":{"created_at":{"description":"CreatedAt is the timestamp when the workload was created.","type":"string"},"group":{"description":"Group is the name of the group this workload belongs to, if any.","type":"string"},"labels":{"additionalProperties":{"type":"string"},"description":"Labels are the container labels (excluding standard ToolHive labels)","type":"object"},"name":{"description":"Name is the name of the workload.\nIt is used as a unique identifier.","type":"string"},"package":{"description":"Package specifies the Workload Package used to create this Workload.","type":"string"},"port":{"description":"Port is the port on which the workload is exposed.\nThis is embedded in the URL.","type":"integer"},"proxy_mode":{"description":"ProxyMode is the proxy mode that clients should use to connect.\nFor stdio transports, this will be the proxy mode (sse or streamable-http).\nFor direct transports (sse/streamable-http), this will be the same as TransportType.","type":"string"},"remote":{"description":"Remote indicates whether this is a remote workload (true) or a container workload (false).","type":"boolean"},"status":{"$ref":"#/components/schemas/runtime.WorkloadStatus"},"status_context":{"description":"StatusContext provides additional context about the workload's status.\nThe exact meaning is determined by the status and the underlying runtime.","type":"string"},"tool_type":{"description":"ToolType is the type of tool this workload represents.\nFor now, it will always be \"mcp\" - representing an MCP server.","type":"string"},"tools":{"description":"ToolsFilter is the filter on tools applied to the workload.","items":{"type":"string"},"type":"array","uniqueItems":false},"transport_type":{"$ref":"#/components/schemas/types.TransportType"},"url":{"description":"URL is the URL of the workload exposed by the ToolHive proxy.","type":"string"}},"type":"object"},"groups.Group":{"properties":{"name":{"type":"string"},"registered_clients":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"ignore.Config":{"description":"IgnoreConfig contains configuration for ignore processing","properties":{"loadGlobal":{"description":"Whether to load global ignore patterns","type":"boolean"},"printOverlays":{"description":"Whether to print resolved overlay paths for debugging","type":"boolean"}},"type":"object"},"permissions.InboundNetworkPermissions":{"description":"Inbound defines inbound network permissions","properties":{"allow_host":{"description":"AllowHost is a list of allowed hosts for inbound connections","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"permissions.NetworkPermissions":{"description":"Network defines network permissions","properties":{"inbound":{"$ref":"#/components/schemas/permissions.InboundNetworkPermissions"},"mode":{"description":"Mode specifies the network mode for the container (e.g., \"host\", \"bridge\", \"none\")\nWhen empty, the default container runtime network mode is used","type":"string"},"outbound":{"$ref":"#/components/schemas/permissions.OutboundNetworkPermissions"}},"type":"object"},"permissions.OutboundNetworkPermissions":{"description":"Outbound defines outbound network permissions","properties":{"allow_host":{"description":"AllowHost is a list of allowed hosts","items":{"type":"string"},"type":"array","uniqueItems":false},"allow_port":{"description":"AllowPort is a list of allowed ports","items":{"type":"integer"},"type":"array","uniqueItems":false},"insecure_allow_all":{"description":"InsecureAllowAll allows all outbound network connections","type":"boolean"}},"type":"object"},"permissions.Profile":{"description":"PermissionProfile is the permission profile to use","properties":{"name":{"description":"Name is the name of the profile","type":"string"},"network":{"$ref":"#/components/schemas/permissions.NetworkPermissions"},"privileged":{"description":"Privileged indicates whether the container should run in privileged mode\nWhen true, the container has access to all host devices and capabilities\nUse with extreme caution as this removes most security isolation","type":"boolean"},"read":{"description":"Read is a list of mount declarations that the container can read from\nThese can be in the following formats:\n- A single path: The same path will be mounted from host to container\n- host-path:container-path: Different paths for host and container\n- resource-uri:container-path: Mount a resource identified by URI to a container path","items":{"type":"string"},"type":"array","uniqueItems":false},"write":{"description":"Write is a list of mount declarations that the container can write to\nThese follow the same format as Read mounts but with write permissions","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"remote.Config":{"description":"RemoteAuthConfig contains OAuth configuration for remote MCP servers","properties":{"authorize_url":{"type":"string"},"callback_port":{"type":"integer"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"client_secret_file":{"type":"string"},"env_vars":{"description":"Environment variables for the client","items":{"$ref":"#/components/schemas/types.EnvVar"},"type":"array","uniqueItems":false},"headers":{"description":"Headers for HTTP requests","items":{"$ref":"#/components/schemas/types.Header"},"type":"array","uniqueItems":false},"issuer":{"description":"OAuth endpoint configuration (from registry)","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"OAuth parameters for server-specific customization","type":"object"},"resource":{"description":"Resource is the OAuth 2.0 resource indicator (RFC 8707).","type":"string"},"scopes":{"items":{"type":"string"},"type":"array","uniqueItems":false},"skip_browser":{"type":"boolean"},"timeout":{"example":"5m","type":"string"},"token_url":{"type":"string"},"use_pkce":{"type":"boolean"}},"type":"object"},"runner.RunConfig":{"properties":{"audit_config":{"$ref":"#/components/schemas/audit.Config"},"audit_config_path":{"description":"AuditConfigPath is the path to the audit configuration file","type":"string"},"authz_config":{"$ref":"#/components/schemas/authz.Config"},"authz_config_path":{"description":"AuthzConfigPath is the path to the authorization configuration file","type":"string"},"base_name":{"description":"BaseName is the base name used for the container (without prefixes)","type":"string"},"cmd_args":{"description":"CmdArgs are the arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"container_labels":{"additionalProperties":{"type":"string"},"description":"ContainerLabels are the labels to apply to the container","type":"object"},"container_name":{"description":"ContainerName is the name of the container","type":"string"},"debug":{"description":"Debug indicates whether debug mode is enabled","type":"boolean"},"env_file_dir":{"description":"EnvFileDir is the directory path to load environment files from","type":"string"},"env_vars":{"additionalProperties":{"type":"string"},"description":"EnvVars are the parsed environment variables as key-value pairs","type":"object"},"group":{"description":"Group is the name of the group this workload belongs to, if any","type":"string"},"host":{"description":"Host is the host for the HTTP proxy","type":"string"},"ignore_config":{"$ref":"#/components/schemas/ignore.Config"},"image":{"description":"Image is the Docker image to run","type":"string"},"isolate_network":{"description":"IsolateNetwork indicates whether to isolate the network for the container","type":"boolean"},"jwks_auth_token_file":{"description":"JWKSAuthTokenFile is the path to file containing auth token for JWKS/OIDC requests","type":"string"},"k8s_pod_template_patch":{"description":"K8sPodTemplatePatch is a JSON string to patch the Kubernetes pod template\nOnly applicable when using Kubernetes runtime","type":"string"},"middleware_configs":{"description":"MiddlewareConfigs contains the list of middleware to apply to the transport\nand the configuration for each middleware.","items":{"$ref":"#/components/schemas/types.MiddlewareConfig"},"type":"array","uniqueItems":false},"name":{"description":"Name is the name of the MCP server","type":"string"},"oidc_config":{"$ref":"#/components/schemas/auth.TokenValidatorConfig"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"permission_profile_name_or_path":{"description":"PermissionProfileNameOrPath is the name or path of the permission profile","type":"string"},"port":{"description":"Port is the port for the HTTP proxy to listen on (host port)","type":"integer"},"proxy_mode":{"$ref":"#/components/schemas/types.ProxyMode"},"remote_auth_config":{"$ref":"#/components/schemas/remote.Config"},"remote_url":{"description":"RemoteURL is the URL of the remote MCP server (if running remotely)","type":"string"},"schema_version":{"description":"SchemaVersion is the version of the RunConfig schema","type":"string"},"secrets":{"description":"Secrets are the secret parameters to pass to the container\nFormat: \"\u003csecret name\u003e,target=\u003ctarget environment variable\u003e\"","items":{"type":"string"},"type":"array","uniqueItems":false},"target_host":{"description":"TargetHost is the host to forward traffic to (only applicable to SSE transport)","type":"string"},"target_port":{"description":"TargetPort is the port for the container to expose (only applicable to SSE transport)","type":"integer"},"telemetry_config":{"$ref":"#/components/schemas/telemetry.Config"},"thv_ca_bundle":{"description":"ThvCABundle is the path to the CA certificate bundle for ToolHive HTTP operations","type":"string"},"token_exchange_config":{"$ref":"#/components/schemas/tokenexchange.Config"},"tools_filter":{"description":"ToolsFilter is the list of tools to filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/runner.ToolOverride"},"description":"ToolsOverride is a map from an actual tool to its overridden name and/or description","type":"object"},"transport":{"description":"Transport is the transport mode (stdio, sse, or streamable-http)","type":"string","x-enum-varnames":["TransportTypeStdio","TransportTypeSSE","TransportTypeStreamableHTTP","TransportTypeInspector"]},"trust_proxy_headers":{"description":"TrustProxyHeaders indicates whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"volumes":{"description":"Volumes are the directory mounts to pass to the container\nFormat: \"host-path:container-path[:ro]\"","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"runner.ToolOverride":{"properties":{"description":{"description":"Description is the redefined description of the tool","type":"string"},"name":{"description":"Name is the redefined name of the tool","type":"string"}},"type":"object"},"runtime.WorkloadStatus":{"description":"Status is the current status of the workload.","type":"string","x-enum-varnames":["WorkloadStatusRunning","WorkloadStatusStopped","WorkloadStatusError","WorkloadStatusStarting","WorkloadStatusStopping","WorkloadStatusUnhealthy","WorkloadStatusRemoving","WorkloadStatusUnknown","WorkloadStatusUnauthenticated"]},"secrets.SecretParameter":{"properties":{"name":{"type":"string"},"target":{"type":"string"}},"type":"object"},"telemetry.Config":{"description":"TelemetryConfig contains the OpenTelemetry configuration","properties":{"customAttributes":{"additionalProperties":{"type":"string"},"description":"CustomAttributes contains custom resource attributes to be added to all telemetry signals.\nThese are parsed from CLI flags (--otel-custom-attributes) or environment variables\n(OTEL_RESOURCE_ATTRIBUTES) as key=value pairs.\nWe use map[string]string for proper JSON serialization instead of []attribute.KeyValue\nwhich doesn't marshal/unmarshal correctly.","type":"object"},"enablePrometheusMetricsPath":{"description":"EnablePrometheusMetricsPath controls whether to expose Prometheus-style /metrics endpoint\nThe metrics are served on the main transport port at /metrics\nThis is separate from OTLP metrics which are sent to the Endpoint","type":"boolean"},"endpoint":{"description":"Endpoint is the OTLP endpoint URL","type":"string"},"environmentVariables":{"description":"EnvironmentVariables is a list of environment variable names that should be\nincluded in telemetry spans as attributes. Only variables in this list will\nbe read from the host machine and included in spans for observability.\nExample: []string{\"NODE_ENV\", \"DEPLOYMENT_ENV\", \"SERVICE_VERSION\"}","items":{"type":"string"},"type":"array","uniqueItems":false},"headers":{"additionalProperties":{"type":"string"},"description":"Headers contains authentication headers for the OTLP endpoint","type":"object"},"insecure":{"description":"Insecure indicates whether to use HTTP instead of HTTPS for the OTLP endpoint","type":"boolean"},"metricsEnabled":{"description":"MetricsEnabled controls whether OTLP metrics are enabled\nWhen false, OTLP metrics are not sent even if an endpoint is configured\nThis is independent of EnablePrometheusMetricsPath","type":"boolean"},"samplingRate":{"description":"SamplingRate is the trace sampling rate (0.0-1.0)\nOnly used when TracingEnabled is true","type":"number"},"serviceName":{"description":"ServiceName is the service name for telemetry","type":"string"},"serviceVersion":{"description":"ServiceVersion is the service version for telemetry","type":"string"},"tracingEnabled":{"description":"TracingEnabled controls whether distributed tracing is enabled\nWhen false, no tracer provider is created even if an endpoint is configured","type":"boolean"}},"type":"object"},"tokenexchange.Config":{"description":"TokenExchangeConfig contains token exchange configuration for external authentication","properties":{"audience":{"description":"Audience is the target audience for the exchanged token","type":"string"},"client_id":{"description":"ClientID is the OAuth 2.0 client identifier","type":"string"},"client_secret":{"description":"ClientSecret is the OAuth 2.0 client secret","type":"string"},"external_token_header_name":{"description":"ExternalTokenHeaderName is the name of the custom header to use when HeaderStrategy is \"custom\"","type":"string"},"header_strategy":{"description":"HeaderStrategy determines how to inject the token\nValid values: HeaderStrategyReplace (default), HeaderStrategyCustom","type":"string"},"scopes":{"description":"Scopes is the list of scopes to request for the exchanged token","items":{"type":"string"},"type":"array","uniqueItems":false},"subject_token_type":{"description":"SubjectTokenType specifies the type of the subject token being exchanged.\nCommon values: tokenTypeAccessToken (default), tokenTypeIDToken, tokenTypeJWT.\nIf empty, defaults to tokenTypeAccessToken.","type":"string"},"token_url":{"description":"TokenURL is the OAuth 2.0 token endpoint URL","type":"string"}},"type":"object"},"types.EnvVar":{"properties":{"default":{"description":"Default is the value to use if the environment variable is not explicitly provided\nOnly used for non-required variables","type":"string"},"description":{"description":"Description is a human-readable explanation of the variable's purpose","type":"string"},"name":{"description":"Name is the environment variable name (e.g., API_KEY)","type":"string"},"required":{"description":"Required indicates whether this environment variable must be provided\nIf true and not provided via command line or secrets, the user will be prompted for a value","type":"boolean"},"secret":{"description":"Secret indicates whether this environment variable contains sensitive information\nIf true, the value will be stored as a secret rather than as a plain environment variable","type":"boolean"}},"type":"object"},"types.Group":{"properties":{"description":{"description":"Description is a human-readable description of the group's purpose and functionality","type":"string"},"name":{"description":"Name is the identifier for the group, used when referencing the group in commands","type":"string"},"remote_servers":{"additionalProperties":{"$ref":"#/components/schemas/types.RemoteServerMetadata"},"description":"RemoteServers is a map of server names to their corresponding remote server definitions within this group","type":"object"},"servers":{"additionalProperties":{"$ref":"#/components/schemas/types.ImageMetadata"},"description":"Servers is a map of server names to their corresponding server definitions within this group","type":"object"}},"type":"object"},"types.Header":{"properties":{"choices":{"description":"Choices provides a list of valid values for the header (optional)","items":{"type":"string"},"type":"array","uniqueItems":false},"default":{"description":"Default is the value to use if the header is not explicitly provided\nOnly used for non-required headers","type":"string"},"description":{"description":"Description is a human-readable explanation of the header's purpose","type":"string"},"name":{"description":"Name is the header name (e.g., X-API-Key, Authorization)","type":"string"},"required":{"description":"Required indicates whether this header must be provided\nIf true and not provided via command line or secrets, the user will be prompted for a value","type":"boolean"},"secret":{"description":"Secret indicates whether this header contains sensitive information\nIf true, the value will be stored as a secret rather than as plain text","type":"boolean"}},"type":"object"},"types.ImageMetadata":{"description":"Container server details (if it's a container server)","properties":{"args":{"description":"Args are the default command-line arguments to pass to the MCP server container.\nThese arguments will be used only if no command-line arguments are provided by the user.\nIf the user provides arguments, they will override these defaults.","items":{"type":"string"},"type":"array","uniqueItems":false},"custom_metadata":{"additionalProperties":{},"description":"CustomMetadata allows for additional user-defined metadata","type":"object"},"description":{"description":"Description is a human-readable description of the server's purpose and functionality","type":"string"},"docker_tags":{"description":"DockerTags lists the available Docker tags for this server image","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"description":"EnvVars defines environment variables that can be passed to the server","items":{"$ref":"#/components/schemas/types.EnvVar"},"type":"array","uniqueItems":false},"image":{"description":"Image is the Docker image reference for the MCP server","type":"string"},"metadata":{"$ref":"#/components/schemas/types.Metadata"},"name":{"description":"Name is the identifier for the MCP server, used when referencing the server in commands\nIf not provided, it will be auto-generated from the registry key","type":"string"},"permissions":{"$ref":"#/components/schemas/permissions.Profile"},"provenance":{"$ref":"#/components/schemas/types.Provenance"},"repository_url":{"description":"RepositoryURL is the URL to the source code repository for the server","type":"string"},"status":{"description":"Status indicates whether the server is currently active or deprecated","type":"string"},"tags":{"description":"Tags are categorization labels for the server to aid in discovery and filtering","items":{"type":"string"},"type":"array","uniqueItems":false},"target_port":{"description":"TargetPort is the port for the container to expose (only applicable to SSE and Streamable HTTP transports)","type":"integer"},"tier":{"description":"Tier represents the tier classification level of the server, e.g., \"Official\" or \"Community\"","type":"string"},"tools":{"description":"Tools is a list of tool names provided by this MCP server","items":{"type":"string"},"type":"array","uniqueItems":false},"transport":{"description":"Transport defines the communication protocol for the server\nFor containers: stdio, sse, or streamable-http\nFor remote servers: sse or streamable-http (stdio not supported)","type":"string"}},"type":"object"},"types.Metadata":{"description":"Metadata contains additional information about the server such as popularity metrics","properties":{"last_updated":{"description":"LastUpdated is the timestamp when the server was last updated, in RFC3339 format","type":"string"},"pulls":{"description":"Pulls indicates how many times the server image has been downloaded","type":"integer"},"stars":{"description":"Stars represents the popularity rating or number of stars for the server","type":"integer"}},"type":"object"},"types.MiddlewareConfig":{"properties":{"parameters":{"description":"Parameters is a JSON object containing the middleware parameters.\nIt is stored as a raw message to allow flexible parameter types.","type":"object"},"type":{"description":"Type is a string representing the middleware type.","type":"string"}},"type":"object"},"types.OAuthConfig":{"description":"OAuthConfig provides OAuth/OIDC configuration for authentication to the remote server\nUsed with the thv proxy command's --remote-auth flags","properties":{"authorize_url":{"description":"AuthorizeURL is the OAuth authorization endpoint URL\nUsed for non-OIDC OAuth flows when issuer is not provided","type":"string"},"callback_port":{"description":"CallbackPort is the specific port to use for the OAuth callback server\nIf not specified, a random available port will be used","type":"integer"},"client_id":{"description":"ClientID is the OAuth client ID for authentication","type":"string"},"issuer":{"description":"Issuer is the OAuth/OIDC issuer URL (e.g., https://accounts.google.com)\nUsed for OIDC discovery to find authorization and token endpoints","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"OAuthParams contains additional OAuth parameters to include in the authorization request\nThese are server-specific parameters like \"prompt\", \"response_mode\", etc.","type":"object"},"resource":{"description":"Resource is the OAuth 2.0 resource indicator (RFC 8707)","type":"string"},"scopes":{"description":"Scopes are the OAuth scopes to request\nIf not specified, defaults to [\"openid\", \"profile\", \"email\"] for OIDC","items":{"type":"string"},"type":"array","uniqueItems":false},"token_url":{"description":"TokenURL is the OAuth token endpoint URL\nUsed for non-OIDC OAuth flows when issuer is not provided","type":"string"},"use_pkce":{"description":"UsePKCE indicates whether to use PKCE for the OAuth flow\nDefaults to true for enhanced security","type":"boolean"}},"type":"object"},"types.Provenance":{"description":"Provenance contains verification and signing metadata","properties":{"attestation":{"$ref":"#/components/schemas/types.VerifiedAttestation"},"cert_issuer":{"type":"string"},"repository_ref":{"type":"string"},"repository_uri":{"type":"string"},"runner_environment":{"type":"string"},"signer_identity":{"type":"string"},"sigstore_url":{"type":"string"}},"type":"object"},"types.ProxyMode":{"description":"ProxyMode is the proxy mode for stdio transport (\"sse\" or \"streamable-http\")","type":"string","x-enum-varnames":["ProxyModeSSE","ProxyModeStreamableHTTP"]},"types.Registry":{"description":"Full registry data","properties":{"groups":{"description":"Groups is a slice of group definitions containing related MCP servers","items":{"$ref":"#/components/schemas/types.Group"},"type":"array","uniqueItems":false},"last_updated":{"description":"LastUpdated is the timestamp when the registry was last updated, in RFC3339 format","type":"string"},"remote_servers":{"additionalProperties":{"$ref":"#/components/schemas/types.RemoteServerMetadata"},"description":"RemoteServers is a map of server names to their corresponding remote server definitions\nThese are MCP servers accessed via HTTP/HTTPS using the thv proxy command","type":"object"},"servers":{"additionalProperties":{"$ref":"#/components/schemas/types.ImageMetadata"},"description":"Servers is a map of server names to their corresponding server definitions","type":"object"},"version":{"description":"Version is the schema version of the registry","type":"string"}},"type":"object"},"types.RemoteServerMetadata":{"description":"Remote server details (if it's a remote server)","properties":{"custom_metadata":{"additionalProperties":{},"description":"CustomMetadata allows for additional user-defined metadata","type":"object"},"description":{"description":"Description is a human-readable description of the server's purpose and functionality","type":"string"},"env_vars":{"description":"EnvVars defines environment variables that can be passed to configure the client\nThese might be needed for client-side configuration when connecting to the remote server","items":{"$ref":"#/components/schemas/types.EnvVar"},"type":"array","uniqueItems":false},"headers":{"description":"Headers defines HTTP headers that can be passed to the remote server for authentication\nThese are used with the thv proxy command's authentication features","items":{"$ref":"#/components/schemas/types.Header"},"type":"array","uniqueItems":false},"metadata":{"$ref":"#/components/schemas/types.Metadata"},"name":{"description":"Name is the identifier for the MCP server, used when referencing the server in commands\nIf not provided, it will be auto-generated from the registry key","type":"string"},"oauth_config":{"$ref":"#/components/schemas/types.OAuthConfig"},"repository_url":{"description":"RepositoryURL is the URL to the source code repository for the server","type":"string"},"status":{"description":"Status indicates whether the server is currently active or deprecated","type":"string"},"tags":{"description":"Tags are categorization labels for the server to aid in discovery and filtering","items":{"type":"string"},"type":"array","uniqueItems":false},"tier":{"description":"Tier represents the tier classification level of the server, e.g., \"Official\" or \"Community\"","type":"string"},"tools":{"description":"Tools is a list of tool names provided by this MCP server","items":{"type":"string"},"type":"array","uniqueItems":false},"transport":{"description":"Transport defines the communication protocol for the server\nFor containers: stdio, sse, or streamable-http\nFor remote servers: sse or streamable-http (stdio not supported)","type":"string"},"url":{"description":"URL is the endpoint URL for the remote MCP server (e.g., https://api.example.com/mcp)","type":"string"}},"type":"object"},"types.TransportType":{"description":"TransportType is the type of transport used for this workload.","type":"string","x-enum-varnames":["TransportTypeStdio","TransportTypeSSE","TransportTypeStreamableHTTP","TransportTypeInspector"]},"types.VerifiedAttestation":{"properties":{"predicate":{},"predicate_type":{"type":"string"}},"type":"object"},"v1.RegistryType":{"description":"Type of registry (file, url, or default)","type":"string","x-enum-varnames":["RegistryTypeFile","RegistryTypeURL","RegistryTypeAPI","RegistryTypeDefault"]},"v1.UpdateRegistryRequest":{"description":"Request containing registry configuration updates","properties":{"allow_private_ip":{"description":"Allow private IP addresses for registry URL or API URL","type":"boolean"},"api_url":{"description":"MCP Registry API URL","type":"string"},"local_path":{"description":"Local registry file path","type":"string"},"url":{"description":"Registry URL (for remote registries)","type":"string"}},"type":"object"},"v1.UpdateRegistryResponse":{"description":"Response containing update result","properties":{"message":{"description":"Status message","type":"string"},"type":{"description":"Registry type after update","type":"string"}},"type":"object"},"v1.bulkClientRequest":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"names":{"description":"Names is the list of client names to operate on.","items":{"type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"type":"array","uniqueItems":false}},"type":"object"},"v1.bulkOperationRequest":{"properties":{"group":{"description":"Group name to operate on (mutually exclusive with names)","type":"string"},"names":{"description":"Names of the workloads to operate on","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.clientStatusResponse":{"properties":{"clients":{"items":{"$ref":"#/components/schemas/client.MCPClientStatus"},"type":"array","uniqueItems":false}},"type":"object"},"v1.createClientRequest":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"description":"Name is the type of the client to register.","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]}},"type":"object"},"v1.createClientResponse":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"description":"Name is the type of the client that was registered.","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]}},"type":"object"},"v1.createGroupRequest":{"properties":{"name":{"description":"Name of the group to create","type":"string"}},"type":"object"},"v1.createGroupResponse":{"properties":{"name":{"description":"Name of the created group","type":"string"}},"type":"object"},"v1.createRequest":{"description":"Request to create a new workload","properties":{"authz_config":{"description":"Authorization configuration","type":"string"},"cmd_arguments":{"description":"Command arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"additionalProperties":{"type":"string"},"description":"Environment variables to set in the container","type":"object"},"group":{"description":"Group name this workload belongs to","type":"string"},"headers":{"items":{"$ref":"#/components/schemas/types.Header"},"type":"array","uniqueItems":false},"host":{"description":"Host to bind to","type":"string"},"image":{"description":"Docker image to use","type":"string"},"name":{"description":"Name of the workload","type":"string"},"network_isolation":{"description":"Whether network isolation is turned on. This applies the rules in the permission profile.","type":"boolean"},"oauth_config":{"$ref":"#/components/schemas/v1.remoteOAuthConfig"},"oidc":{"$ref":"#/components/schemas/v1.oidcOptions"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"proxy_mode":{"description":"Proxy mode to use","type":"string"},"proxy_port":{"description":"Port for the HTTP proxy to listen on","type":"integer"},"secrets":{"description":"Secret parameters to inject","items":{"$ref":"#/components/schemas/secrets.SecretParameter"},"type":"array","uniqueItems":false},"target_port":{"description":"Port to expose from the container","type":"integer"},"tools":{"description":"Tools filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/v1.toolOverride"},"description":"Tools override","type":"object"},"transport":{"description":"Transport configuration","type":"string"},"trust_proxy_headers":{"description":"Whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"url":{"description":"Remote server specific fields","type":"string"},"volumes":{"description":"Volume mounts","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.createSecretRequest":{"description":"Request to create a new secret","properties":{"key":{"description":"Secret key name","type":"string"},"value":{"description":"Secret value","type":"string"}},"type":"object"},"v1.createSecretResponse":{"description":"Response after creating a secret","properties":{"key":{"description":"Secret key that was created","type":"string"},"message":{"description":"Success message","type":"string"}},"type":"object"},"v1.createWorkloadResponse":{"description":"Response after successfully creating a workload","properties":{"name":{"description":"Name of the created workload","type":"string"},"port":{"description":"Port the workload is listening on","type":"integer"}},"type":"object"},"v1.getRegistryResponse":{"description":"Response containing registry details","properties":{"last_updated":{"description":"Last updated timestamp","type":"string"},"name":{"description":"Name of the registry","type":"string"},"registry":{"$ref":"#/components/schemas/types.Registry"},"server_count":{"description":"Number of servers in the registry","type":"integer"},"source":{"description":"Source of the registry (URL, file path, or empty string for built-in)","type":"string"},"type":{"description":"Type of registry (file, url, or default)","type":"string","x-enum-varnames":["RegistryTypeFile","RegistryTypeURL","RegistryTypeAPI","RegistryTypeDefault"]},"version":{"description":"Version of the registry schema","type":"string"}},"type":"object"},"v1.getSecretsProviderResponse":{"description":"Response containing secrets provider details","properties":{"capabilities":{"$ref":"#/components/schemas/v1.providerCapabilitiesResponse"},"name":{"description":"Name of the secrets provider","type":"string"},"provider_type":{"description":"Type of the secrets provider","type":"string"}},"type":"object"},"v1.getServerResponse":{"description":"Response containing server details","properties":{"is_remote":{"description":"Indicates if this is a remote server","type":"boolean"},"remote_server":{"$ref":"#/components/schemas/types.RemoteServerMetadata"},"server":{"$ref":"#/components/schemas/types.ImageMetadata"}},"type":"object"},"v1.groupListResponse":{"properties":{"groups":{"description":"List of groups","items":{"$ref":"#/components/schemas/groups.Group"},"type":"array","uniqueItems":false}},"type":"object"},"v1.listSecretsResponse":{"description":"Response containing a list of secret keys","properties":{"keys":{"description":"List of secret keys","items":{"$ref":"#/components/schemas/v1.secretKeyResponse"},"type":"array","uniqueItems":false}},"type":"object"},"v1.listServersResponse":{"description":"Response containing a list of servers","properties":{"remote_servers":{"description":"List of remote servers in the registry (if any)","items":{"$ref":"#/components/schemas/types.RemoteServerMetadata"},"type":"array","uniqueItems":false},"servers":{"description":"List of container servers in the registry","items":{"$ref":"#/components/schemas/types.ImageMetadata"},"type":"array","uniqueItems":false}},"type":"object"},"v1.oidcOptions":{"description":"OIDC configuration options","properties":{"audience":{"description":"Expected audience","type":"string"},"client_id":{"description":"OAuth2 client ID","type":"string"},"client_secret":{"description":"OAuth2 client secret","type":"string"},"introspection_url":{"description":"Token introspection URL for OIDC","type":"string"},"issuer":{"description":"OIDC issuer URL","type":"string"},"jwks_url":{"description":"JWKS URL for key verification","type":"string"}},"type":"object"},"v1.providerCapabilitiesResponse":{"description":"Capabilities of the secrets provider","properties":{"can_cleanup":{"description":"Whether the provider can cleanup all secrets","type":"boolean"},"can_delete":{"description":"Whether the provider can delete secrets","type":"boolean"},"can_list":{"description":"Whether the provider can list secrets","type":"boolean"},"can_read":{"description":"Whether the provider can read secrets","type":"boolean"},"can_write":{"description":"Whether the provider can write secrets","type":"boolean"}},"type":"object"},"v1.registryInfo":{"description":"Basic information about a registry","properties":{"last_updated":{"description":"Last updated timestamp","type":"string"},"name":{"description":"Name of the registry","type":"string"},"server_count":{"description":"Number of servers in the registry","type":"integer"},"source":{"description":"Source of the registry (URL, file path, or empty string for built-in)","type":"string"},"type":{"$ref":"#/components/schemas/v1.RegistryType"},"version":{"description":"Version of the registry schema","type":"string"}},"type":"object"},"v1.registryListResponse":{"description":"Response containing a list of registries","properties":{"registries":{"description":"List of registries","items":{"$ref":"#/components/schemas/v1.registryInfo"},"type":"array","uniqueItems":false}},"type":"object"},"v1.remoteOAuthConfig":{"description":"OAuth configuration for remote server authentication","properties":{"authorize_url":{"description":"OAuth authorization endpoint URL (alternative to issuer for non-OIDC OAuth)","type":"string"},"callback_port":{"description":"Specific port for OAuth callback server","type":"integer"},"client_id":{"description":"OAuth client ID for authentication","type":"string"},"client_secret":{"$ref":"#/components/schemas/secrets.SecretParameter"},"issuer":{"description":"OAuth/OIDC issuer URL (e.g., https://accounts.google.com)","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"Additional OAuth parameters for server-specific customization","type":"object"},"resource":{"description":"OAuth 2.0 resource indicator (RFC 8707)","type":"string"},"scopes":{"description":"OAuth scopes to request","items":{"type":"string"},"type":"array","uniqueItems":false},"skip_browser":{"description":"Whether to skip opening browser for OAuth flow (defaults to false)","type":"boolean"},"token_url":{"description":"OAuth token endpoint URL (alternative to issuer for non-OIDC OAuth)","type":"string"},"use_pkce":{"description":"Whether to use PKCE for the OAuth flow","type":"boolean"}},"type":"object"},"v1.secretKeyResponse":{"description":"Secret key information","properties":{"description":{"description":"Optional description of the secret","type":"string"},"key":{"description":"Secret key name","type":"string"}},"type":"object"},"v1.setupSecretsRequest":{"description":"Request to setup a secrets provider","properties":{"password":{"description":"Password for encrypted provider (optional, can be set via environment variable)\nTODO Review environment variable for this","type":"string"},"provider_type":{"description":"Type of the secrets provider (encrypted, 1password, none)","type":"string"}},"type":"object"},"v1.setupSecretsResponse":{"description":"Response after initializing a secrets provider","properties":{"message":{"description":"Success message","type":"string"},"provider_type":{"description":"Type of the secrets provider that was setup","type":"string"}},"type":"object"},"v1.toolOverride":{"description":"Tool override","properties":{"description":{"description":"Description of the tool","type":"string"},"name":{"description":"Name of the tool","type":"string"}},"type":"object"},"v1.updateRequest":{"description":"Request to update an existing workload (name cannot be changed)","properties":{"authz_config":{"description":"Authorization configuration","type":"string"},"cmd_arguments":{"description":"Command arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"additionalProperties":{"type":"string"},"description":"Environment variables to set in the container","type":"object"},"group":{"description":"Group name this workload belongs to","type":"string"},"headers":{"items":{"$ref":"#/components/schemas/types.Header"},"type":"array","uniqueItems":false},"host":{"description":"Host to bind to","type":"string"},"image":{"description":"Docker image to use","type":"string"},"network_isolation":{"description":"Whether network isolation is turned on. This applies the rules in the permission profile.","type":"boolean"},"oauth_config":{"$ref":"#/components/schemas/v1.remoteOAuthConfig"},"oidc":{"$ref":"#/components/schemas/v1.oidcOptions"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"proxy_mode":{"description":"Proxy mode to use","type":"string"},"proxy_port":{"description":"Port for the HTTP proxy to listen on","type":"integer"},"secrets":{"description":"Secret parameters to inject","items":{"$ref":"#/components/schemas/secrets.SecretParameter"},"type":"array","uniqueItems":false},"target_port":{"description":"Port to expose from the container","type":"integer"},"tools":{"description":"Tools filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/v1.toolOverride"},"description":"Tools override","type":"object"},"transport":{"description":"Transport configuration","type":"string"},"trust_proxy_headers":{"description":"Whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"url":{"description":"Remote server specific fields","type":"string"},"volumes":{"description":"Volume mounts","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.updateSecretRequest":{"description":"Request to update an existing secret","properties":{"value":{"description":"New secret value","type":"string"}},"type":"object"},"v1.updateSecretResponse":{"description":"Response after updating a secret","properties":{"key":{"description":"Secret key that was updated","type":"string"},"message":{"description":"Success message","type":"string"}},"type":"object"},"v1.versionResponse":{"properties":{"version":{"type":"string"}},"type":"object"},"v1.workloadListResponse":{"description":"Response containing a list of workloads","properties":{"workloads":{"description":"List of container information for each workload","items":{"$ref":"#/components/schemas/core.Workload"},"type":"array","uniqueItems":false}},"type":"object"},"v1.workloadStatusResponse":{"description":"Response containing workload status information","properties":{"status":{"description":"Current status of the workload","type":"string","x-enum-varnames":["WorkloadStatusRunning","WorkloadStatusStopped","WorkloadStatusError","WorkloadStatusStarting","WorkloadStatusStopping","WorkloadStatusUnhealthy","WorkloadStatusRemoving","WorkloadStatusUnknown","WorkloadStatusUnauthenticated"]}},"type":"object"}}}, + "components": {"schemas":{"audit.Config":{"description":"AuditConfig contains the audit logging configuration","properties":{"component":{"description":"Component is the component name to use in audit events","type":"string"},"event_types":{"description":"EventTypes specifies which event types to audit. If empty, all events are audited.","items":{"type":"string"},"type":"array","uniqueItems":false},"exclude_event_types":{"description":"ExcludeEventTypes specifies which event types to exclude from auditing.\nThis takes precedence over EventTypes.","items":{"type":"string"},"type":"array","uniqueItems":false},"include_request_data":{"description":"IncludeRequestData determines whether to include request data in audit logs","type":"boolean"},"include_response_data":{"description":"IncludeResponseData determines whether to include response data in audit logs","type":"boolean"},"log_file":{"description":"LogFile specifies the file path for audit logs. If empty, logs to stdout.","type":"string"},"max_data_size":{"description":"MaxDataSize limits the size of request/response data included in audit logs (in bytes)","type":"integer"}},"type":"object"},"auth.TokenValidatorConfig":{"description":"OIDCConfig contains OIDC configuration","properties":{"allowPrivateIP":{"description":"AllowPrivateIP allows JWKS/OIDC endpoints on private IP addresses","type":"boolean"},"audience":{"description":"Audience is the expected audience for the token","type":"string"},"authTokenFile":{"description":"AuthTokenFile is the path to file containing bearer token for authentication","type":"string"},"cacertPath":{"description":"CACertPath is the path to the CA certificate bundle for HTTPS requests","type":"string"},"clientID":{"description":"ClientID is the OIDC client ID","type":"string"},"clientSecret":{"description":"ClientSecret is the optional OIDC client secret for introspection","type":"string"},"insecureAllowHTTP":{"description":"InsecureAllowHTTP allows HTTP (non-HTTPS) OIDC issuers for development/testing\nWARNING: This is insecure and should NEVER be used in production","type":"boolean"},"introspectionURL":{"description":"IntrospectionURL is the optional introspection endpoint for validating tokens","type":"string"},"issuer":{"description":"Issuer is the OIDC issuer URL (e.g., https://accounts.google.com)","type":"string"},"jwksurl":{"description":"JWKSURL is the URL to fetch the JWKS from","type":"string"},"resourceURL":{"description":"ResourceURL is the explicit resource URL for OAuth discovery (RFC 9728)","type":"string"}},"type":"object"},"authz.CedarConfig":{"description":"Cedar is the Cedar-specific configuration.\nThis is only used when Type is ConfigTypeCedarV1.","properties":{"entities_json":{"description":"EntitiesJSON is the JSON string representing Cedar entities","type":"string"},"policies":{"description":"Policies is a list of Cedar policy strings","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"authz.Config":{"description":"AuthzConfig contains the authorization configuration","properties":{"cedar":{"$ref":"#/components/schemas/authz.CedarConfig"},"type":{"$ref":"#/components/schemas/authz.ConfigType"},"version":{"description":"Version is the version of the configuration format.","type":"string"}},"type":"object"},"authz.ConfigType":{"description":"Type is the type of authorization configuration.","type":"string","x-enum-varnames":["ConfigTypeCedarV1"]},"client.MCPClient":{"type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"client.MCPClientStatus":{"properties":{"client_type":{"description":"ClientType is the type of MCP client","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"installed":{"description":"Installed indicates whether the client is installed on the system","type":"boolean"},"registered":{"description":"Registered indicates whether the client is registered in the ToolHive configuration","type":"boolean"}},"type":"object"},"client.RegisteredClient":{"properties":{"groups":{"items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"$ref":"#/components/schemas/client.MCPClient"}},"type":"object"},"core.Workload":{"properties":{"created_at":{"description":"CreatedAt is the timestamp when the workload was created.","type":"string"},"group":{"description":"Group is the name of the group this workload belongs to, if any.","type":"string"},"labels":{"additionalProperties":{"type":"string"},"description":"Labels are the container labels (excluding standard ToolHive labels)","type":"object"},"name":{"description":"Name is the name of the workload.\nIt is used as a unique identifier.","type":"string"},"package":{"description":"Package specifies the Workload Package used to create this Workload.","type":"string"},"port":{"description":"Port is the port on which the workload is exposed.\nThis is embedded in the URL.","type":"integer"},"proxy_mode":{"description":"ProxyMode is the proxy mode that clients should use to connect.\nFor stdio transports, this will be the proxy mode (sse or streamable-http).\nFor direct transports (sse/streamable-http), this will be the same as TransportType.","type":"string"},"remote":{"description":"Remote indicates whether this is a remote workload (true) or a container workload (false).","type":"boolean"},"status":{"$ref":"#/components/schemas/runtime.WorkloadStatus"},"status_context":{"description":"StatusContext provides additional context about the workload's status.\nThe exact meaning is determined by the status and the underlying runtime.","type":"string"},"tool_type":{"description":"ToolType is the type of tool this workload represents.\nFor now, it will always be \"mcp\" - representing an MCP server.","type":"string"},"tools":{"description":"ToolsFilter is the filter on tools applied to the workload.","items":{"type":"string"},"type":"array","uniqueItems":false},"transport_type":{"$ref":"#/components/schemas/types.TransportType"},"url":{"description":"URL is the URL of the workload exposed by the ToolHive proxy.","type":"string"}},"type":"object"},"groups.Group":{"properties":{"name":{"type":"string"},"registered_clients":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"ignore.Config":{"description":"IgnoreConfig contains configuration for ignore processing","properties":{"loadGlobal":{"description":"Whether to load global ignore patterns","type":"boolean"},"printOverlays":{"description":"Whether to print resolved overlay paths for debugging","type":"boolean"}},"type":"object"},"permissions.InboundNetworkPermissions":{"description":"Inbound defines inbound network permissions","properties":{"allow_host":{"description":"AllowHost is a list of allowed hosts for inbound connections","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"permissions.NetworkPermissions":{"description":"Network defines network permissions","properties":{"inbound":{"$ref":"#/components/schemas/permissions.InboundNetworkPermissions"},"mode":{"description":"Mode specifies the network mode for the container (e.g., \"host\", \"bridge\", \"none\")\nWhen empty, the default container runtime network mode is used","type":"string"},"outbound":{"$ref":"#/components/schemas/permissions.OutboundNetworkPermissions"}},"type":"object"},"permissions.OutboundNetworkPermissions":{"description":"Outbound defines outbound network permissions","properties":{"allow_host":{"description":"AllowHost is a list of allowed hosts","items":{"type":"string"},"type":"array","uniqueItems":false},"allow_port":{"description":"AllowPort is a list of allowed ports","items":{"type":"integer"},"type":"array","uniqueItems":false},"insecure_allow_all":{"description":"InsecureAllowAll allows all outbound network connections","type":"boolean"}},"type":"object"},"permissions.Profile":{"description":"PermissionProfile is the permission profile to use","properties":{"name":{"description":"Name is the name of the profile","type":"string"},"network":{"$ref":"#/components/schemas/permissions.NetworkPermissions"},"privileged":{"description":"Privileged indicates whether the container should run in privileged mode\nWhen true, the container has access to all host devices and capabilities\nUse with extreme caution as this removes most security isolation","type":"boolean"},"read":{"description":"Read is a list of mount declarations that the container can read from\nThese can be in the following formats:\n- A single path: The same path will be mounted from host to container\n- host-path:container-path: Different paths for host and container\n- resource-uri:container-path: Mount a resource identified by URI to a container path","items":{"type":"string"},"type":"array","uniqueItems":false},"write":{"description":"Write is a list of mount declarations that the container can write to\nThese follow the same format as Read mounts but with write permissions","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"registry.EnvVar":{"properties":{"default":{"description":"Default is the value to use if the environment variable is not explicitly provided\nOnly used for non-required variables","type":"string"},"description":{"description":"Description is a human-readable explanation of the variable's purpose","type":"string"},"name":{"description":"Name is the environment variable name (e.g., API_KEY)","type":"string"},"required":{"description":"Required indicates whether this environment variable must be provided\nIf true and not provided via command line or secrets, the user will be prompted for a value","type":"boolean"},"secret":{"description":"Secret indicates whether this environment variable contains sensitive information\nIf true, the value will be stored as a secret rather than as a plain environment variable","type":"boolean"}},"type":"object"},"registry.Group":{"properties":{"description":{"description":"Description is a human-readable description of the group's purpose and functionality","type":"string"},"name":{"description":"Name is the identifier for the group, used when referencing the group in commands","type":"string"},"remote_servers":{"additionalProperties":{"$ref":"#/components/schemas/registry.RemoteServerMetadata"},"description":"RemoteServers is a map of server names to their corresponding remote server definitions within this group","type":"object"},"servers":{"additionalProperties":{"$ref":"#/components/schemas/registry.ImageMetadata"},"description":"Servers is a map of server names to their corresponding server definitions within this group","type":"object"}},"type":"object"},"registry.Header":{"properties":{"choices":{"description":"Choices provides a list of valid values for the header (optional)","items":{"type":"string"},"type":"array","uniqueItems":false},"default":{"description":"Default is the value to use if the header is not explicitly provided\nOnly used for non-required headers","type":"string"},"description":{"description":"Description is a human-readable explanation of the header's purpose","type":"string"},"name":{"description":"Name is the header name (e.g., X-API-Key, Authorization)","type":"string"},"required":{"description":"Required indicates whether this header must be provided\nIf true and not provided via command line or secrets, the user will be prompted for a value","type":"boolean"},"secret":{"description":"Secret indicates whether this header contains sensitive information\nIf true, the value will be stored as a secret rather than as plain text","type":"boolean"}},"type":"object"},"registry.ImageMetadata":{"description":"Container server details (if it's a container server)","properties":{"args":{"description":"Args are the default command-line arguments to pass to the MCP server container.\nThese arguments will be used only if no command-line arguments are provided by the user.\nIf the user provides arguments, they will override these defaults.","items":{"type":"string"},"type":"array","uniqueItems":false},"custom_metadata":{"additionalProperties":{},"description":"CustomMetadata allows for additional user-defined metadata","type":"object"},"description":{"description":"Description is a human-readable description of the server's purpose and functionality","type":"string"},"docker_tags":{"description":"DockerTags lists the available Docker tags for this server image","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"description":"EnvVars defines environment variables that can be passed to the server","items":{"$ref":"#/components/schemas/registry.EnvVar"},"type":"array","uniqueItems":false},"image":{"description":"Image is the Docker image reference for the MCP server","type":"string"},"metadata":{"$ref":"#/components/schemas/registry.Metadata"},"name":{"description":"Name is the identifier for the MCP server, used when referencing the server in commands\nIf not provided, it will be auto-generated from the registry key","type":"string"},"permissions":{"$ref":"#/components/schemas/permissions.Profile"},"provenance":{"$ref":"#/components/schemas/registry.Provenance"},"repository_url":{"description":"RepositoryURL is the URL to the source code repository for the server","type":"string"},"status":{"description":"Status indicates whether the server is currently active or deprecated","type":"string"},"tags":{"description":"Tags are categorization labels for the server to aid in discovery and filtering","items":{"type":"string"},"type":"array","uniqueItems":false},"target_port":{"description":"TargetPort is the port for the container to expose (only applicable to SSE and Streamable HTTP transports)","type":"integer"},"tier":{"description":"Tier represents the tier classification level of the server, e.g., \"Official\" or \"Community\"","type":"string"},"tools":{"description":"Tools is a list of tool names provided by this MCP server","items":{"type":"string"},"type":"array","uniqueItems":false},"transport":{"description":"Transport defines the communication protocol for the server\nFor containers: stdio, sse, or streamable-http\nFor remote servers: sse or streamable-http (stdio not supported)","type":"string"}},"type":"object"},"registry.Metadata":{"description":"Metadata contains additional information about the server such as popularity metrics","properties":{"last_updated":{"description":"LastUpdated is the timestamp when the server was last updated, in RFC3339 format","type":"string"},"pulls":{"description":"Pulls indicates how many times the server image has been downloaded","type":"integer"},"stars":{"description":"Stars represents the popularity rating or number of stars for the server","type":"integer"}},"type":"object"},"registry.OAuthConfig":{"description":"OAuthConfig provides OAuth/OIDC configuration for authentication to the remote server\nUsed with the thv proxy command's --remote-auth flags","properties":{"authorize_url":{"description":"AuthorizeURL is the OAuth authorization endpoint URL\nUsed for non-OIDC OAuth flows when issuer is not provided","type":"string"},"callback_port":{"description":"CallbackPort is the specific port to use for the OAuth callback server\nIf not specified, a random available port will be used","type":"integer"},"client_id":{"description":"ClientID is the OAuth client ID for authentication","type":"string"},"issuer":{"description":"Issuer is the OAuth/OIDC issuer URL (e.g., https://accounts.google.com)\nUsed for OIDC discovery to find authorization and token endpoints","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"OAuthParams contains additional OAuth parameters to include in the authorization request\nThese are server-specific parameters like \"prompt\", \"response_mode\", etc.","type":"object"},"resource":{"description":"Resource is the OAuth 2.0 resource indicator (RFC 8707)","type":"string"},"scopes":{"description":"Scopes are the OAuth scopes to request\nIf not specified, defaults to [\"openid\", \"profile\", \"email\"] for OIDC","items":{"type":"string"},"type":"array","uniqueItems":false},"token_url":{"description":"TokenURL is the OAuth token endpoint URL\nUsed for non-OIDC OAuth flows when issuer is not provided","type":"string"},"use_pkce":{"description":"UsePKCE indicates whether to use PKCE for the OAuth flow\nDefaults to true for enhanced security","type":"boolean"}},"type":"object"},"registry.Provenance":{"description":"Provenance contains verification and signing metadata","properties":{"attestation":{"$ref":"#/components/schemas/registry.VerifiedAttestation"},"cert_issuer":{"type":"string"},"repository_ref":{"type":"string"},"repository_uri":{"type":"string"},"runner_environment":{"type":"string"},"signer_identity":{"type":"string"},"sigstore_url":{"type":"string"}},"type":"object"},"registry.Registry":{"description":"Full registry data","properties":{"groups":{"description":"Groups is a slice of group definitions containing related MCP servers","items":{"$ref":"#/components/schemas/registry.Group"},"type":"array","uniqueItems":false},"last_updated":{"description":"LastUpdated is the timestamp when the registry was last updated, in RFC3339 format","type":"string"},"remote_servers":{"additionalProperties":{"$ref":"#/components/schemas/registry.RemoteServerMetadata"},"description":"RemoteServers is a map of server names to their corresponding remote server definitions\nThese are MCP servers accessed via HTTP/HTTPS using the thv proxy command","type":"object"},"servers":{"additionalProperties":{"$ref":"#/components/schemas/registry.ImageMetadata"},"description":"Servers is a map of server names to their corresponding server definitions","type":"object"},"version":{"description":"Version is the schema version of the registry","type":"string"}},"type":"object"},"registry.RemoteServerMetadata":{"description":"Remote server details (if it's a remote server)","properties":{"custom_metadata":{"additionalProperties":{},"description":"CustomMetadata allows for additional user-defined metadata","type":"object"},"description":{"description":"Description is a human-readable description of the server's purpose and functionality","type":"string"},"env_vars":{"description":"EnvVars defines environment variables that can be passed to configure the client\nThese might be needed for client-side configuration when connecting to the remote server","items":{"$ref":"#/components/schemas/registry.EnvVar"},"type":"array","uniqueItems":false},"headers":{"description":"Headers defines HTTP headers that can be passed to the remote server for authentication\nThese are used with the thv proxy command's authentication features","items":{"$ref":"#/components/schemas/registry.Header"},"type":"array","uniqueItems":false},"metadata":{"$ref":"#/components/schemas/registry.Metadata"},"name":{"description":"Name is the identifier for the MCP server, used when referencing the server in commands\nIf not provided, it will be auto-generated from the registry key","type":"string"},"oauth_config":{"$ref":"#/components/schemas/registry.OAuthConfig"},"repository_url":{"description":"RepositoryURL is the URL to the source code repository for the server","type":"string"},"status":{"description":"Status indicates whether the server is currently active or deprecated","type":"string"},"tags":{"description":"Tags are categorization labels for the server to aid in discovery and filtering","items":{"type":"string"},"type":"array","uniqueItems":false},"tier":{"description":"Tier represents the tier classification level of the server, e.g., \"Official\" or \"Community\"","type":"string"},"tools":{"description":"Tools is a list of tool names provided by this MCP server","items":{"type":"string"},"type":"array","uniqueItems":false},"transport":{"description":"Transport defines the communication protocol for the server\nFor containers: stdio, sse, or streamable-http\nFor remote servers: sse or streamable-http (stdio not supported)","type":"string"},"url":{"description":"URL is the endpoint URL for the remote MCP server (e.g., https://api.example.com/mcp)","type":"string"}},"type":"object"},"registry.VerifiedAttestation":{"properties":{"predicate":{},"predicate_type":{"type":"string"}},"type":"object"},"remote.Config":{"description":"RemoteAuthConfig contains OAuth configuration for remote MCP servers","properties":{"authorize_url":{"type":"string"},"callback_port":{"type":"integer"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"client_secret_file":{"type":"string"},"env_vars":{"description":"Environment variables for the client","items":{"$ref":"#/components/schemas/registry.EnvVar"},"type":"array","uniqueItems":false},"headers":{"description":"Headers for HTTP requests","items":{"$ref":"#/components/schemas/registry.Header"},"type":"array","uniqueItems":false},"issuer":{"description":"OAuth endpoint configuration (from registry)","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"OAuth parameters for server-specific customization","type":"object"},"resource":{"description":"Resource is the OAuth 2.0 resource indicator (RFC 8707).","type":"string"},"scopes":{"items":{"type":"string"},"type":"array","uniqueItems":false},"skip_browser":{"type":"boolean"},"timeout":{"example":"5m","type":"string"},"token_url":{"type":"string"},"use_pkce":{"type":"boolean"}},"type":"object"},"runner.RunConfig":{"properties":{"audit_config":{"$ref":"#/components/schemas/audit.Config"},"audit_config_path":{"description":"AuditConfigPath is the path to the audit configuration file","type":"string"},"authz_config":{"$ref":"#/components/schemas/authz.Config"},"authz_config_path":{"description":"AuthzConfigPath is the path to the authorization configuration file","type":"string"},"base_name":{"description":"BaseName is the base name used for the container (without prefixes)","type":"string"},"cmd_args":{"description":"CmdArgs are the arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"container_labels":{"additionalProperties":{"type":"string"},"description":"ContainerLabels are the labels to apply to the container","type":"object"},"container_name":{"description":"ContainerName is the name of the container","type":"string"},"debug":{"description":"Debug indicates whether debug mode is enabled","type":"boolean"},"env_file_dir":{"description":"EnvFileDir is the directory path to load environment files from","type":"string"},"env_vars":{"additionalProperties":{"type":"string"},"description":"EnvVars are the parsed environment variables as key-value pairs","type":"object"},"group":{"description":"Group is the name of the group this workload belongs to, if any","type":"string"},"host":{"description":"Host is the host for the HTTP proxy","type":"string"},"ignore_config":{"$ref":"#/components/schemas/ignore.Config"},"image":{"description":"Image is the Docker image to run","type":"string"},"isolate_network":{"description":"IsolateNetwork indicates whether to isolate the network for the container","type":"boolean"},"jwks_auth_token_file":{"description":"JWKSAuthTokenFile is the path to file containing auth token for JWKS/OIDC requests","type":"string"},"k8s_pod_template_patch":{"description":"K8sPodTemplatePatch is a JSON string to patch the Kubernetes pod template\nOnly applicable when using Kubernetes runtime","type":"string"},"middleware_configs":{"description":"MiddlewareConfigs contains the list of middleware to apply to the transport\nand the configuration for each middleware.","items":{"$ref":"#/components/schemas/types.MiddlewareConfig"},"type":"array","uniqueItems":false},"name":{"description":"Name is the name of the MCP server","type":"string"},"oidc_config":{"$ref":"#/components/schemas/auth.TokenValidatorConfig"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"permission_profile_name_or_path":{"description":"PermissionProfileNameOrPath is the name or path of the permission profile","type":"string"},"port":{"description":"Port is the port for the HTTP proxy to listen on (host port)","type":"integer"},"proxy_mode":{"$ref":"#/components/schemas/types.ProxyMode"},"remote_auth_config":{"$ref":"#/components/schemas/remote.Config"},"remote_url":{"description":"RemoteURL is the URL of the remote MCP server (if running remotely)","type":"string"},"schema_version":{"description":"SchemaVersion is the version of the RunConfig schema","type":"string"},"secrets":{"description":"Secrets are the secret parameters to pass to the container\nFormat: \"\u003csecret name\u003e,target=\u003ctarget environment variable\u003e\"","items":{"type":"string"},"type":"array","uniqueItems":false},"target_host":{"description":"TargetHost is the host to forward traffic to (only applicable to SSE transport)","type":"string"},"target_port":{"description":"TargetPort is the port for the container to expose (only applicable to SSE transport)","type":"integer"},"telemetry_config":{"$ref":"#/components/schemas/telemetry.Config"},"thv_ca_bundle":{"description":"ThvCABundle is the path to the CA certificate bundle for ToolHive HTTP operations","type":"string"},"token_exchange_config":{"$ref":"#/components/schemas/tokenexchange.Config"},"tools_filter":{"description":"ToolsFilter is the list of tools to filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/runner.ToolOverride"},"description":"ToolsOverride is a map from an actual tool to its overridden name and/or description","type":"object"},"transport":{"description":"Transport is the transport mode (stdio, sse, or streamable-http)","type":"string","x-enum-varnames":["TransportTypeStdio","TransportTypeSSE","TransportTypeStreamableHTTP","TransportTypeInspector"]},"trust_proxy_headers":{"description":"TrustProxyHeaders indicates whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"volumes":{"description":"Volumes are the directory mounts to pass to the container\nFormat: \"host-path:container-path[:ro]\"","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"runner.ToolOverride":{"properties":{"description":{"description":"Description is the redefined description of the tool","type":"string"},"name":{"description":"Name is the redefined name of the tool","type":"string"}},"type":"object"},"runtime.WorkloadStatus":{"description":"Status is the current status of the workload.","type":"string","x-enum-varnames":["WorkloadStatusRunning","WorkloadStatusStopped","WorkloadStatusError","WorkloadStatusStarting","WorkloadStatusStopping","WorkloadStatusUnhealthy","WorkloadStatusRemoving","WorkloadStatusUnknown","WorkloadStatusUnauthenticated"]},"secrets.SecretParameter":{"properties":{"name":{"type":"string"},"target":{"type":"string"}},"type":"object"},"telemetry.Config":{"description":"TelemetryConfig contains the OpenTelemetry configuration","properties":{"customAttributes":{"additionalProperties":{"type":"string"},"description":"CustomAttributes contains custom resource attributes to be added to all telemetry signals.\nThese are parsed from CLI flags (--otel-custom-attributes) or environment variables\n(OTEL_RESOURCE_ATTRIBUTES) as key=value pairs.\nWe use map[string]string for proper JSON serialization instead of []attribute.KeyValue\nwhich doesn't marshal/unmarshal correctly.","type":"object"},"enablePrometheusMetricsPath":{"description":"EnablePrometheusMetricsPath controls whether to expose Prometheus-style /metrics endpoint\nThe metrics are served on the main transport port at /metrics\nThis is separate from OTLP metrics which are sent to the Endpoint","type":"boolean"},"endpoint":{"description":"Endpoint is the OTLP endpoint URL","type":"string"},"environmentVariables":{"description":"EnvironmentVariables is a list of environment variable names that should be\nincluded in telemetry spans as attributes. Only variables in this list will\nbe read from the host machine and included in spans for observability.\nExample: []string{\"NODE_ENV\", \"DEPLOYMENT_ENV\", \"SERVICE_VERSION\"}","items":{"type":"string"},"type":"array","uniqueItems":false},"headers":{"additionalProperties":{"type":"string"},"description":"Headers contains authentication headers for the OTLP endpoint","type":"object"},"insecure":{"description":"Insecure indicates whether to use HTTP instead of HTTPS for the OTLP endpoint","type":"boolean"},"metricsEnabled":{"description":"MetricsEnabled controls whether OTLP metrics are enabled\nWhen false, OTLP metrics are not sent even if an endpoint is configured\nThis is independent of EnablePrometheusMetricsPath","type":"boolean"},"samplingRate":{"description":"SamplingRate is the trace sampling rate (0.0-1.0)\nOnly used when TracingEnabled is true","type":"number"},"serviceName":{"description":"ServiceName is the service name for telemetry","type":"string"},"serviceVersion":{"description":"ServiceVersion is the service version for telemetry","type":"string"},"tracingEnabled":{"description":"TracingEnabled controls whether distributed tracing is enabled\nWhen false, no tracer provider is created even if an endpoint is configured","type":"boolean"}},"type":"object"},"tokenexchange.Config":{"description":"TokenExchangeConfig contains token exchange configuration for external authentication","properties":{"audience":{"description":"Audience is the target audience for the exchanged token","type":"string"},"client_id":{"description":"ClientID is the OAuth 2.0 client identifier","type":"string"},"client_secret":{"description":"ClientSecret is the OAuth 2.0 client secret","type":"string"},"external_token_header_name":{"description":"ExternalTokenHeaderName is the name of the custom header to use when HeaderStrategy is \"custom\"","type":"string"},"header_strategy":{"description":"HeaderStrategy determines how to inject the token\nValid values: HeaderStrategyReplace (default), HeaderStrategyCustom","type":"string"},"scopes":{"description":"Scopes is the list of scopes to request for the exchanged token","items":{"type":"string"},"type":"array","uniqueItems":false},"subject_token_type":{"description":"SubjectTokenType specifies the type of the subject token being exchanged.\nCommon values: tokenTypeAccessToken (default), tokenTypeIDToken, tokenTypeJWT.\nIf empty, defaults to tokenTypeAccessToken.","type":"string"},"token_url":{"description":"TokenURL is the OAuth 2.0 token endpoint URL","type":"string"}},"type":"object"},"types.MiddlewareConfig":{"properties":{"parameters":{"description":"Parameters is a JSON object containing the middleware parameters.\nIt is stored as a raw message to allow flexible parameter types.","type":"object"},"type":{"description":"Type is a string representing the middleware type.","type":"string"}},"type":"object"},"types.ProxyMode":{"description":"ProxyMode is the proxy mode for stdio transport (\"sse\" or \"streamable-http\")","type":"string","x-enum-varnames":["ProxyModeSSE","ProxyModeStreamableHTTP"]},"types.TransportType":{"description":"TransportType is the type of transport used for this workload.","type":"string","x-enum-varnames":["TransportTypeStdio","TransportTypeSSE","TransportTypeStreamableHTTP","TransportTypeInspector"]},"v1.RegistryType":{"description":"Type of registry (file, url, or default)","type":"string","x-enum-varnames":["RegistryTypeFile","RegistryTypeURL","RegistryTypeAPI","RegistryTypeDefault"]},"v1.UpdateRegistryRequest":{"description":"Request containing registry configuration updates","properties":{"allow_private_ip":{"description":"Allow private IP addresses for registry URL or API URL","type":"boolean"},"api_url":{"description":"MCP Registry API URL","type":"string"},"local_path":{"description":"Local registry file path","type":"string"},"url":{"description":"Registry URL (for remote registries)","type":"string"}},"type":"object"},"v1.UpdateRegistryResponse":{"description":"Response containing update result","properties":{"message":{"description":"Status message","type":"string"},"type":{"description":"Registry type after update","type":"string"}},"type":"object"},"v1.bulkClientRequest":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"names":{"description":"Names is the list of client names to operate on.","items":{"type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]},"type":"array","uniqueItems":false}},"type":"object"},"v1.bulkOperationRequest":{"properties":{"group":{"description":"Group name to operate on (mutually exclusive with names)","type":"string"},"names":{"description":"Names of the workloads to operate on","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.clientStatusResponse":{"properties":{"clients":{"items":{"$ref":"#/components/schemas/client.MCPClientStatus"},"type":"array","uniqueItems":false}},"type":"object"},"v1.createClientRequest":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"description":"Name is the type of the client to register.","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]}},"type":"object"},"v1.createClientResponse":{"properties":{"groups":{"description":"Groups is the list of groups configured on the client.","items":{"type":"string"},"type":"array","uniqueItems":false},"name":{"description":"Name is the type of the client that was registered.","type":"string","x-enum-varnames":["RooCode","Cline","Cursor","VSCodeInsider","VSCode","ClaudeCode","Windsurf","WindsurfJetBrains","AmpCli","AmpVSCode","AmpCursor","AmpVSCodeInsider","AmpWindsurf","LMStudio","Goose","Trae","Continue","OpenCode","Kiro","Antigravity"]}},"type":"object"},"v1.createGroupRequest":{"properties":{"name":{"description":"Name of the group to create","type":"string"}},"type":"object"},"v1.createGroupResponse":{"properties":{"name":{"description":"Name of the created group","type":"string"}},"type":"object"},"v1.createRequest":{"description":"Request to create a new workload","properties":{"authz_config":{"description":"Authorization configuration","type":"string"},"cmd_arguments":{"description":"Command arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"additionalProperties":{"type":"string"},"description":"Environment variables to set in the container","type":"object"},"group":{"description":"Group name this workload belongs to","type":"string"},"headers":{"items":{"$ref":"#/components/schemas/registry.Header"},"type":"array","uniqueItems":false},"host":{"description":"Host to bind to","type":"string"},"image":{"description":"Docker image to use","type":"string"},"name":{"description":"Name of the workload","type":"string"},"network_isolation":{"description":"Whether network isolation is turned on. This applies the rules in the permission profile.","type":"boolean"},"oauth_config":{"$ref":"#/components/schemas/v1.remoteOAuthConfig"},"oidc":{"$ref":"#/components/schemas/v1.oidcOptions"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"proxy_mode":{"description":"Proxy mode to use","type":"string"},"proxy_port":{"description":"Port for the HTTP proxy to listen on","type":"integer"},"secrets":{"description":"Secret parameters to inject","items":{"$ref":"#/components/schemas/secrets.SecretParameter"},"type":"array","uniqueItems":false},"target_port":{"description":"Port to expose from the container","type":"integer"},"tools":{"description":"Tools filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/v1.toolOverride"},"description":"Tools override","type":"object"},"transport":{"description":"Transport configuration","type":"string"},"trust_proxy_headers":{"description":"Whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"url":{"description":"Remote server specific fields","type":"string"},"volumes":{"description":"Volume mounts","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.createSecretRequest":{"description":"Request to create a new secret","properties":{"key":{"description":"Secret key name","type":"string"},"value":{"description":"Secret value","type":"string"}},"type":"object"},"v1.createSecretResponse":{"description":"Response after creating a secret","properties":{"key":{"description":"Secret key that was created","type":"string"},"message":{"description":"Success message","type":"string"}},"type":"object"},"v1.createWorkloadResponse":{"description":"Response after successfully creating a workload","properties":{"name":{"description":"Name of the created workload","type":"string"},"port":{"description":"Port the workload is listening on","type":"integer"}},"type":"object"},"v1.getRegistryResponse":{"description":"Response containing registry details","properties":{"last_updated":{"description":"Last updated timestamp","type":"string"},"name":{"description":"Name of the registry","type":"string"},"registry":{"$ref":"#/components/schemas/registry.Registry"},"server_count":{"description":"Number of servers in the registry","type":"integer"},"source":{"description":"Source of the registry (URL, file path, or empty string for built-in)","type":"string"},"type":{"description":"Type of registry (file, url, or default)","type":"string","x-enum-varnames":["RegistryTypeFile","RegistryTypeURL","RegistryTypeAPI","RegistryTypeDefault"]},"version":{"description":"Version of the registry schema","type":"string"}},"type":"object"},"v1.getSecretsProviderResponse":{"description":"Response containing secrets provider details","properties":{"capabilities":{"$ref":"#/components/schemas/v1.providerCapabilitiesResponse"},"name":{"description":"Name of the secrets provider","type":"string"},"provider_type":{"description":"Type of the secrets provider","type":"string"}},"type":"object"},"v1.getServerResponse":{"description":"Response containing server details","properties":{"is_remote":{"description":"Indicates if this is a remote server","type":"boolean"},"remote_server":{"$ref":"#/components/schemas/registry.RemoteServerMetadata"},"server":{"$ref":"#/components/schemas/registry.ImageMetadata"}},"type":"object"},"v1.groupListResponse":{"properties":{"groups":{"description":"List of groups","items":{"$ref":"#/components/schemas/groups.Group"},"type":"array","uniqueItems":false}},"type":"object"},"v1.listSecretsResponse":{"description":"Response containing a list of secret keys","properties":{"keys":{"description":"List of secret keys","items":{"$ref":"#/components/schemas/v1.secretKeyResponse"},"type":"array","uniqueItems":false}},"type":"object"},"v1.listServersResponse":{"description":"Response containing a list of servers","properties":{"remote_servers":{"description":"List of remote servers in the registry (if any)","items":{"$ref":"#/components/schemas/registry.RemoteServerMetadata"},"type":"array","uniqueItems":false},"servers":{"description":"List of container servers in the registry","items":{"$ref":"#/components/schemas/registry.ImageMetadata"},"type":"array","uniqueItems":false}},"type":"object"},"v1.oidcOptions":{"description":"OIDC configuration options","properties":{"audience":{"description":"Expected audience","type":"string"},"client_id":{"description":"OAuth2 client ID","type":"string"},"client_secret":{"description":"OAuth2 client secret","type":"string"},"introspection_url":{"description":"Token introspection URL for OIDC","type":"string"},"issuer":{"description":"OIDC issuer URL","type":"string"},"jwks_url":{"description":"JWKS URL for key verification","type":"string"}},"type":"object"},"v1.providerCapabilitiesResponse":{"description":"Capabilities of the secrets provider","properties":{"can_cleanup":{"description":"Whether the provider can cleanup all secrets","type":"boolean"},"can_delete":{"description":"Whether the provider can delete secrets","type":"boolean"},"can_list":{"description":"Whether the provider can list secrets","type":"boolean"},"can_read":{"description":"Whether the provider can read secrets","type":"boolean"},"can_write":{"description":"Whether the provider can write secrets","type":"boolean"}},"type":"object"},"v1.registryInfo":{"description":"Basic information about a registry","properties":{"last_updated":{"description":"Last updated timestamp","type":"string"},"name":{"description":"Name of the registry","type":"string"},"server_count":{"description":"Number of servers in the registry","type":"integer"},"source":{"description":"Source of the registry (URL, file path, or empty string for built-in)","type":"string"},"type":{"$ref":"#/components/schemas/v1.RegistryType"},"version":{"description":"Version of the registry schema","type":"string"}},"type":"object"},"v1.registryListResponse":{"description":"Response containing a list of registries","properties":{"registries":{"description":"List of registries","items":{"$ref":"#/components/schemas/v1.registryInfo"},"type":"array","uniqueItems":false}},"type":"object"},"v1.remoteOAuthConfig":{"description":"OAuth configuration for remote server authentication","properties":{"authorize_url":{"description":"OAuth authorization endpoint URL (alternative to issuer for non-OIDC OAuth)","type":"string"},"callback_port":{"description":"Specific port for OAuth callback server","type":"integer"},"client_id":{"description":"OAuth client ID for authentication","type":"string"},"client_secret":{"$ref":"#/components/schemas/secrets.SecretParameter"},"issuer":{"description":"OAuth/OIDC issuer URL (e.g., https://accounts.google.com)","type":"string"},"oauth_params":{"additionalProperties":{"type":"string"},"description":"Additional OAuth parameters for server-specific customization","type":"object"},"resource":{"description":"OAuth 2.0 resource indicator (RFC 8707)","type":"string"},"scopes":{"description":"OAuth scopes to request","items":{"type":"string"},"type":"array","uniqueItems":false},"skip_browser":{"description":"Whether to skip opening browser for OAuth flow (defaults to false)","type":"boolean"},"token_url":{"description":"OAuth token endpoint URL (alternative to issuer for non-OIDC OAuth)","type":"string"},"use_pkce":{"description":"Whether to use PKCE for the OAuth flow","type":"boolean"}},"type":"object"},"v1.secretKeyResponse":{"description":"Secret key information","properties":{"description":{"description":"Optional description of the secret","type":"string"},"key":{"description":"Secret key name","type":"string"}},"type":"object"},"v1.setupSecretsRequest":{"description":"Request to setup a secrets provider","properties":{"password":{"description":"Password for encrypted provider (optional, can be set via environment variable)\nTODO Review environment variable for this","type":"string"},"provider_type":{"description":"Type of the secrets provider (encrypted, 1password, none)","type":"string"}},"type":"object"},"v1.setupSecretsResponse":{"description":"Response after initializing a secrets provider","properties":{"message":{"description":"Success message","type":"string"},"provider_type":{"description":"Type of the secrets provider that was setup","type":"string"}},"type":"object"},"v1.toolOverride":{"description":"Tool override","properties":{"description":{"description":"Description of the tool","type":"string"},"name":{"description":"Name of the tool","type":"string"}},"type":"object"},"v1.updateRequest":{"description":"Request to update an existing workload (name cannot be changed)","properties":{"authz_config":{"description":"Authorization configuration","type":"string"},"cmd_arguments":{"description":"Command arguments to pass to the container","items":{"type":"string"},"type":"array","uniqueItems":false},"env_vars":{"additionalProperties":{"type":"string"},"description":"Environment variables to set in the container","type":"object"},"group":{"description":"Group name this workload belongs to","type":"string"},"headers":{"items":{"$ref":"#/components/schemas/registry.Header"},"type":"array","uniqueItems":false},"host":{"description":"Host to bind to","type":"string"},"image":{"description":"Docker image to use","type":"string"},"network_isolation":{"description":"Whether network isolation is turned on. This applies the rules in the permission profile.","type":"boolean"},"oauth_config":{"$ref":"#/components/schemas/v1.remoteOAuthConfig"},"oidc":{"$ref":"#/components/schemas/v1.oidcOptions"},"permission_profile":{"$ref":"#/components/schemas/permissions.Profile"},"proxy_mode":{"description":"Proxy mode to use","type":"string"},"proxy_port":{"description":"Port for the HTTP proxy to listen on","type":"integer"},"secrets":{"description":"Secret parameters to inject","items":{"$ref":"#/components/schemas/secrets.SecretParameter"},"type":"array","uniqueItems":false},"target_port":{"description":"Port to expose from the container","type":"integer"},"tools":{"description":"Tools filter","items":{"type":"string"},"type":"array","uniqueItems":false},"tools_override":{"additionalProperties":{"$ref":"#/components/schemas/v1.toolOverride"},"description":"Tools override","type":"object"},"transport":{"description":"Transport configuration","type":"string"},"trust_proxy_headers":{"description":"Whether to trust X-Forwarded-* headers from reverse proxies","type":"boolean"},"url":{"description":"Remote server specific fields","type":"string"},"volumes":{"description":"Volume mounts","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"v1.updateSecretRequest":{"description":"Request to update an existing secret","properties":{"value":{"description":"New secret value","type":"string"}},"type":"object"},"v1.updateSecretResponse":{"description":"Response after updating a secret","properties":{"key":{"description":"Secret key that was updated","type":"string"},"message":{"description":"Success message","type":"string"}},"type":"object"},"v1.versionResponse":{"properties":{"version":{"type":"string"}},"type":"object"},"v1.workloadListResponse":{"description":"Response containing a list of workloads","properties":{"workloads":{"description":"List of container information for each workload","items":{"$ref":"#/components/schemas/core.Workload"},"type":"array","uniqueItems":false}},"type":"object"},"v1.workloadStatusResponse":{"description":"Response containing workload status information","properties":{"status":{"description":"Current status of the workload","type":"string","x-enum-varnames":["WorkloadStatusRunning","WorkloadStatusStopped","WorkloadStatusError","WorkloadStatusStarting","WorkloadStatusStopping","WorkloadStatusUnhealthy","WorkloadStatusRemoving","WorkloadStatusUnknown","WorkloadStatusUnauthenticated"]}},"type":"object"}}}, "info": {"description":"This is the ToolHive API server.","title":"ToolHive API","version":"1.0"}, "externalDocs": {"description":"","url":""}, "paths": {"/api/openapi.json":{"get":{"description":"Returns the OpenAPI specification for the API","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"OpenAPI specification"}},"summary":"Get OpenAPI specification","tags":["system"]}},"/api/v1beta/clients":{"get":{"description":"List all registered clients in ToolHive","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/client.RegisteredClient"},"type":"array"}}},"description":"OK"}},"summary":"List all clients","tags":["clients"]},"post":{"description":"Register a new client with ToolHive","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createClientRequest"}}},"description":"Client to register","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createClientResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"}},"summary":"Register a new client","tags":["clients"]}},"/api/v1beta/clients/register":{"post":{"description":"Register multiple clients with ToolHive","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkClientRequest"}}},"description":"Clients to register","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/v1.createClientResponse"},"type":"array"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"}},"summary":"Register multiple clients","tags":["clients"]}},"/api/v1beta/clients/unregister":{"post":{"description":"Unregister multiple clients from ToolHive","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkClientRequest"}}},"description":"Clients to unregister","required":true},"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"}},"summary":"Unregister multiple clients","tags":["clients"]}},"/api/v1beta/clients/{name}":{"delete":{"description":"Unregister a client from ToolHive","parameters":[{"description":"Client name to unregister","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"}},"summary":"Unregister a client","tags":["clients"]}},"/api/v1beta/clients/{name}/groups/{group}":{"delete":{"description":"Unregister a client from a specific group in ToolHive","parameters":[{"description":"Client name to unregister","in":"path","name":"name","required":true,"schema":{"type":"string"}},{"description":"Group name to remove client from","in":"path","name":"group","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Client or group not found"}},"summary":"Unregister a client from a specific group","tags":["clients"]}},"/api/v1beta/discovery/clients":{"get":{"description":"List all clients compatible with ToolHive and their status","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.clientStatusResponse"}}},"description":"OK"}},"summary":"List all clients status","tags":["discovery"]}},"/api/v1beta/groups":{"get":{"description":"Get a list of all groups","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.groupListResponse"}}},"description":"OK"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"List all groups","tags":["groups"]},"post":{"description":"Create a new group with the specified name","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createGroupRequest"}}},"description":"Group creation request","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createGroupResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"409":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Conflict"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Create a new group","tags":["groups"]}},"/api/v1beta/groups/{name}":{"delete":{"description":"Delete a group by name.","parameters":[{"description":"Group name","in":"path","name":"name","required":true,"schema":{"type":"string"}},{"description":"Delete all workloads in the group (default: false, moves workloads to default group)","in":"query","name":"with-workloads","schema":{"type":"boolean"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Delete a group","tags":["groups"]},"get":{"description":"Get details of a specific group","parameters":[{"description":"Group name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/groups.Group"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Get group details","tags":["groups"]}},"/api/v1beta/registry":{"get":{"description":"Get a list of the current registries","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.registryListResponse"}}},"description":"OK"}},"summary":"List registries","tags":["registry"]},"post":{"description":"Add a new registry","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"501":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Implemented"}},"summary":"Add a registry","tags":["registry"]}},"/api/v1beta/registry/{name}":{"delete":{"description":"Remove a specific registry","parameters":[{"description":"Registry name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Remove a registry","tags":["registry"]},"get":{"description":"Get details of a specific registry","parameters":[{"description":"Registry name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.getRegistryResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get a registry","tags":["registry"]},"put":{"description":"Update registry URL or local path for the default registry","parameters":[{"description":"Registry name (must be 'default')","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.UpdateRegistryRequest"}}},"description":"Registry configuration","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.UpdateRegistryResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Update registry configuration","tags":["registry"]}},"/api/v1beta/registry/{name}/servers":{"get":{"description":"Get a list of servers in a specific registry","parameters":[{"description":"Registry name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.listServersResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"List servers in a registry","tags":["registry"]}},"/api/v1beta/registry/{name}/servers/{serverName}":{"get":{"description":"Get details of a specific server in a registry","parameters":[{"description":"Registry name","in":"path","name":"name","required":true,"schema":{"type":"string"}},{"description":"ImageMetadata name","in":"path","name":"serverName","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.getServerResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get a server from a registry","tags":["registry"]}},"/api/v1beta/secrets":{"post":{"description":"Setup the secrets provider with the specified type and configuration.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.setupSecretsRequest"}}},"description":"Setup secrets provider request","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.setupSecretsResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Setup or reconfigure secrets provider","tags":["secrets"]}},"/api/v1beta/secrets/default":{"get":{"description":"Get details of the default secrets provider","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.getSecretsProviderResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Get secrets provider details","tags":["secrets"]}},"/api/v1beta/secrets/default/keys":{"get":{"description":"Get a list of all secret keys from the default provider","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.listSecretsResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup"},"405":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Method Not Allowed - Provider doesn't support listing"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"List secrets","tags":["secrets"]},"post":{"description":"Create a new secret in the default provider (encrypted provider only)","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createSecretRequest"}}},"description":"Create secret request","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createSecretResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup"},"405":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Method Not Allowed - Provider doesn't support writing"},"409":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Conflict - Secret already exists"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Create a new secret","tags":["secrets"]}},"/api/v1beta/secrets/default/keys/{key}":{"delete":{"description":"Delete a secret from the default provider (encrypted provider only)","parameters":[{"description":"Secret key","in":"path","name":"key","required":true,"schema":{"type":"string"}}],"responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup or secret not found"},"405":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Method Not Allowed - Provider doesn't support deletion"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Delete a secret","tags":["secrets"]},"put":{"description":"Update an existing secret in the default provider (encrypted provider only)","parameters":[{"description":"Secret key","in":"path","name":"key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.updateSecretRequest"}}},"description":"Update secret request","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.updateSecretResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found - Provider not setup or secret not found"},"405":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Method Not Allowed - Provider doesn't support writing"},"500":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Internal Server Error"}},"summary":"Update a secret","tags":["secrets"]}},"/api/v1beta/version":{"get":{"description":"Returns the current version of the server","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.versionResponse"}}},"description":"OK"}},"summary":"Get server version","tags":["version"]}},"/api/v1beta/workloads":{"get":{"description":"Get a list of all running workloads, optionally filtered by group","parameters":[{"description":"List all workloads, including stopped ones","in":"query","name":"all","schema":{"type":"boolean"}},{"description":"Filter workloads by group name","in":"query","name":"group","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.workloadListResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Group not found"}},"summary":"List all workloads","tags":["workloads"]},"post":{"description":"Create and start a new workload","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createRequest"}}},"description":"Create workload request","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createWorkloadResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"409":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Conflict"}},"summary":"Create a new workload","tags":["workloads"]}},"/api/v1beta/workloads/delete":{"post":{"description":"Delete multiple workloads by name or by group","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkOperationRequest"}}},"description":"Bulk delete request (names or group)","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"}},"summary":"Delete workloads in bulk","tags":["workloads"]}},"/api/v1beta/workloads/restart":{"post":{"description":"Restart multiple workloads by name or by group","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkOperationRequest"}}},"description":"Bulk restart request (names or group)","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"}},"summary":"Restart workloads in bulk","tags":["workloads"]}},"/api/v1beta/workloads/stop":{"post":{"description":"Stop multiple workloads by name or by group","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.bulkOperationRequest"}}},"description":"Bulk stop request (names or group)","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"}},"summary":"Stop workloads in bulk","tags":["workloads"]}},"/api/v1beta/workloads/{name}":{"delete":{"description":"Delete a workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Delete a workload","tags":["workloads"]},"get":{"description":"Get details of a specific workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createRequest"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get workload details","tags":["workloads"]}},"/api/v1beta/workloads/{name}/edit":{"post":{"description":"Update an existing workload configuration","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.updateRequest"}}},"description":"Update workload request","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.createWorkloadResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Update workload","tags":["workloads"]}},"/api/v1beta/workloads/{name}/export":{"get":{"description":"Export a workload's run configuration as JSON","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/runner.RunConfig"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Export workload configuration","tags":["workloads"]}},"/api/v1beta/workloads/{name}/logs":{"get":{"description":"Retrieve at most 100 lines of logs for a specific workload by name.","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"Logs for the specified workload"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid workload name"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get logs for a specific workload","tags":["logs"]}},"/api/v1beta/workloads/{name}/proxy-logs":{"get":{"description":"Retrieve proxy logs for a specific workload by name from the file system.","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}},"text/plain":{"schema":{"type":"string"}}},"description":"Proxy logs for the specified workload"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Invalid workload name"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Proxy logs not found for workload"}},"summary":"Get proxy logs for a specific workload","tags":["logs"]}},"/api/v1beta/workloads/{name}/restart":{"post":{"description":"Restart a running workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Restart a workload","tags":["workloads"]}},"/api/v1beta/workloads/{name}/status":{"get":{"description":"Get the current status of a specific workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.workloadStatusResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Get workload status","tags":["workloads"]}},"/api/v1beta/workloads/{name}/stop":{"post":{"description":"Stop a running workload","parameters":[{"description":"Workload name","in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Accepted"},"400":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Bad Request"},"404":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Not Found"}},"summary":"Stop a workload","tags":["workloads"]}},"/health":{"get":{"description":"Check if the API is healthy","responses":{"204":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"No Content"}},"summary":"Health check","tags":["system"]}}}, diff --git a/docs/server/swagger.yaml b/docs/server/swagger.yaml index 514aa3312..97fd3623a 100644 --- a/docs/server/swagger.yaml +++ b/docs/server/swagger.yaml @@ -339,435 +339,289 @@ components: type: array uniqueItems: false type: object - remote.Config: - description: RemoteAuthConfig contains OAuth configuration for remote MCP servers + registry.EnvVar: properties: - authorize_url: + default: + description: |- + Default is the value to use if the environment variable is not explicitly provided + Only used for non-required variables type: string - callback_port: - type: integer - client_id: + description: + description: Description is a human-readable explanation of the variable's + purpose type: string - client_secret: + name: + description: Name is the environment variable name (e.g., API_KEY) type: string - client_secret_file: + required: + description: |- + Required indicates whether this environment variable must be provided + If true and not provided via command line or secrets, the user will be prompted for a value + type: boolean + secret: + description: |- + Secret indicates whether this environment variable contains sensitive information + If true, the value will be stored as a secret rather than as a plain environment variable + type: boolean + type: object + registry.Group: + properties: + description: + description: Description is a human-readable description of the group's + purpose and functionality type: string - env_vars: - description: Environment variables for the client - items: - $ref: '#/components/schemas/types.EnvVar' - type: array - uniqueItems: false - headers: - description: Headers for HTTP requests - items: - $ref: '#/components/schemas/types.Header' - type: array - uniqueItems: false - issuer: - description: OAuth endpoint configuration (from registry) + name: + description: Name is the identifier for the group, used when referencing + the group in commands type: string - oauth_params: + remote_servers: additionalProperties: - type: string - description: OAuth parameters for server-specific customization + $ref: '#/components/schemas/registry.RemoteServerMetadata' + description: RemoteServers is a map of server names to their corresponding + remote server definitions within this group type: object - resource: - description: Resource is the OAuth 2.0 resource indicator (RFC 8707). - type: string - scopes: + servers: + additionalProperties: + $ref: '#/components/schemas/registry.ImageMetadata' + description: Servers is a map of server names to their corresponding server + definitions within this group + type: object + type: object + registry.Header: + properties: + choices: + description: Choices provides a list of valid values for the header (optional) items: type: string type: array uniqueItems: false - skip_browser: - type: boolean - timeout: - example: 5m + default: + description: |- + Default is the value to use if the header is not explicitly provided + Only used for non-required headers type: string - token_url: + description: + description: Description is a human-readable explanation of the header's + purpose type: string - use_pkce: + name: + description: Name is the header name (e.g., X-API-Key, Authorization) + type: string + required: + description: |- + Required indicates whether this header must be provided + If true and not provided via command line or secrets, the user will be prompted for a value + type: boolean + secret: + description: |- + Secret indicates whether this header contains sensitive information + If true, the value will be stored as a secret rather than as plain text type: boolean type: object - runner.RunConfig: + registry.ImageMetadata: + description: Container server details (if it's a container server) properties: - audit_config: - $ref: '#/components/schemas/audit.Config' - audit_config_path: - description: AuditConfigPath is the path to the audit configuration file - type: string - authz_config: - $ref: '#/components/schemas/authz.Config' - authz_config_path: - description: AuthzConfigPath is the path to the authorization configuration - file - type: string - base_name: - description: BaseName is the base name used for the container (without prefixes) - type: string - cmd_args: - description: CmdArgs are the arguments to pass to the container + args: + description: |- + Args are the default command-line arguments to pass to the MCP server container. + These arguments will be used only if no command-line arguments are provided by the user. + If the user provides arguments, they will override these defaults. items: type: string type: array uniqueItems: false - container_labels: - additionalProperties: - type: string - description: ContainerLabels are the labels to apply to the container + custom_metadata: + additionalProperties: {} + description: CustomMetadata allows for additional user-defined metadata type: object - container_name: - description: ContainerName is the name of the container - type: string - debug: - description: Debug indicates whether debug mode is enabled - type: boolean - env_file_dir: - description: EnvFileDir is the directory path to load environment files - from + description: + description: Description is a human-readable description of the server's + purpose and functionality type: string - env_vars: - additionalProperties: + docker_tags: + description: DockerTags lists the available Docker tags for this server + image + items: type: string - description: EnvVars are the parsed environment variables as key-value pairs - type: object - group: - description: Group is the name of the group this workload belongs to, if - any - type: string - host: - description: Host is the host for the HTTP proxy - type: string - ignore_config: - $ref: '#/components/schemas/ignore.Config' - image: - description: Image is the Docker image to run - type: string - isolate_network: - description: IsolateNetwork indicates whether to isolate the network for - the container - type: boolean - jwks_auth_token_file: - description: JWKSAuthTokenFile is the path to file containing auth token - for JWKS/OIDC requests - type: string - k8s_pod_template_patch: - description: |- - K8sPodTemplatePatch is a JSON string to patch the Kubernetes pod template - Only applicable when using Kubernetes runtime - type: string - middleware_configs: - description: |- - MiddlewareConfigs contains the list of middleware to apply to the transport - and the configuration for each middleware. + type: array + uniqueItems: false + env_vars: + description: EnvVars defines environment variables that can be passed to + the server items: - $ref: '#/components/schemas/types.MiddlewareConfig' + $ref: '#/components/schemas/registry.EnvVar' type: array uniqueItems: false + image: + description: Image is the Docker image reference for the MCP server + type: string + metadata: + $ref: '#/components/schemas/registry.Metadata' name: - description: Name is the name of the MCP server + description: |- + Name is the identifier for the MCP server, used when referencing the server in commands + If not provided, it will be auto-generated from the registry key type: string - oidc_config: - $ref: '#/components/schemas/auth.TokenValidatorConfig' - permission_profile: + permissions: $ref: '#/components/schemas/permissions.Profile' - permission_profile_name_or_path: - description: PermissionProfileNameOrPath is the name or path of the permission - profile - type: string - port: - description: Port is the port for the HTTP proxy to listen on (host port) - type: integer - proxy_mode: - $ref: '#/components/schemas/types.ProxyMode' - remote_auth_config: - $ref: '#/components/schemas/remote.Config' - remote_url: - description: RemoteURL is the URL of the remote MCP server (if running remotely) + provenance: + $ref: '#/components/schemas/registry.Provenance' + repository_url: + description: RepositoryURL is the URL to the source code repository for + the server type: string - schema_version: - description: SchemaVersion is the version of the RunConfig schema + status: + description: Status indicates whether the server is currently active or + deprecated type: string - secrets: - description: |- - Secrets are the secret parameters to pass to the container - Format: ",target=" + tags: + description: Tags are categorization labels for the server to aid in discovery + and filtering items: type: string type: array uniqueItems: false - target_host: - description: TargetHost is the host to forward traffic to (only applicable - to SSE transport) - type: string target_port: description: TargetPort is the port for the container to expose (only applicable - to SSE transport) + to SSE and Streamable HTTP transports) type: integer - telemetry_config: - $ref: '#/components/schemas/telemetry.Config' - thv_ca_bundle: - description: ThvCABundle is the path to the CA certificate bundle for ToolHive - HTTP operations + tier: + description: Tier represents the tier classification level of the server, + e.g., "Official" or "Community" type: string - token_exchange_config: - $ref: '#/components/schemas/tokenexchange.Config' - tools_filter: - description: ToolsFilter is the list of tools to filter + tools: + description: Tools is a list of tool names provided by this MCP server items: type: string type: array uniqueItems: false - tools_override: - additionalProperties: - $ref: '#/components/schemas/runner.ToolOverride' - description: ToolsOverride is a map from an actual tool to its overridden - name and/or description - type: object transport: - description: Transport is the transport mode (stdio, sse, or streamable-http) - type: string - x-enum-varnames: - - TransportTypeStdio - - TransportTypeSSE - - TransportTypeStreamableHTTP - - TransportTypeInspector - trust_proxy_headers: - description: TrustProxyHeaders indicates whether to trust X-Forwarded-* - headers from reverse proxies - type: boolean - volumes: description: |- - Volumes are the directory mounts to pass to the container - Format: "host-path:container-path[:ro]" - items: - type: string - type: array - uniqueItems: false - type: object - runner.ToolOverride: - properties: - description: - description: Description is the redefined description of the tool - type: string - name: - description: Name is the redefined name of the tool + Transport defines the communication protocol for the server + For containers: stdio, sse, or streamable-http + For remote servers: sse or streamable-http (stdio not supported) type: string type: object - runtime.WorkloadStatus: - description: Status is the current status of the workload. - type: string - x-enum-varnames: - - WorkloadStatusRunning - - WorkloadStatusStopped - - WorkloadStatusError - - WorkloadStatusStarting - - WorkloadStatusStopping - - WorkloadStatusUnhealthy - - WorkloadStatusRemoving - - WorkloadStatusUnknown - - WorkloadStatusUnauthenticated - secrets.SecretParameter: + registry.Metadata: + description: Metadata contains additional information about the server such + as popularity metrics properties: - name: - type: string - target: + last_updated: + description: LastUpdated is the timestamp when the server was last updated, + in RFC3339 format type: string + pulls: + description: Pulls indicates how many times the server image has been downloaded + type: integer + stars: + description: Stars represents the popularity rating or number of stars for + the server + type: integer type: object - telemetry.Config: - description: TelemetryConfig contains the OpenTelemetry configuration + registry.OAuthConfig: + description: |- + OAuthConfig provides OAuth/OIDC configuration for authentication to the remote server + Used with the thv proxy command's --remote-auth flags properties: - customAttributes: - additionalProperties: - type: string - description: |- - CustomAttributes contains custom resource attributes to be added to all telemetry signals. - These are parsed from CLI flags (--otel-custom-attributes) or environment variables - (OTEL_RESOURCE_ATTRIBUTES) as key=value pairs. - We use map[string]string for proper JSON serialization instead of []attribute.KeyValue - which doesn't marshal/unmarshal correctly. - type: object - enablePrometheusMetricsPath: - description: |- - EnablePrometheusMetricsPath controls whether to expose Prometheus-style /metrics endpoint - The metrics are served on the main transport port at /metrics - This is separate from OTLP metrics which are sent to the Endpoint - type: boolean - endpoint: - description: Endpoint is the OTLP endpoint URL - type: string - environmentVariables: - description: |- - EnvironmentVariables is a list of environment variable names that should be - included in telemetry spans as attributes. Only variables in this list will - be read from the host machine and included in spans for observability. - Example: []string{"NODE_ENV", "DEPLOYMENT_ENV", "SERVICE_VERSION"} - items: - type: string - type: array - uniqueItems: false - headers: - additionalProperties: - type: string - description: Headers contains authentication headers for the OTLP endpoint - type: object - insecure: - description: Insecure indicates whether to use HTTP instead of HTTPS for - the OTLP endpoint - type: boolean - metricsEnabled: - description: |- - MetricsEnabled controls whether OTLP metrics are enabled - When false, OTLP metrics are not sent even if an endpoint is configured - This is independent of EnablePrometheusMetricsPath - type: boolean - samplingRate: + authorize_url: description: |- - SamplingRate is the trace sampling rate (0.0-1.0) - Only used when TracingEnabled is true - type: number - serviceName: - description: ServiceName is the service name for telemetry - type: string - serviceVersion: - description: ServiceVersion is the service version for telemetry + AuthorizeURL is the OAuth authorization endpoint URL + Used for non-OIDC OAuth flows when issuer is not provided type: string - tracingEnabled: + callback_port: description: |- - TracingEnabled controls whether distributed tracing is enabled - When false, no tracer provider is created even if an endpoint is configured - type: boolean - type: object - tokenexchange.Config: - description: TokenExchangeConfig contains token exchange configuration for external - authentication - properties: - audience: - description: Audience is the target audience for the exchanged token - type: string + CallbackPort is the specific port to use for the OAuth callback server + If not specified, a random available port will be used + type: integer client_id: - description: ClientID is the OAuth 2.0 client identifier - type: string - client_secret: - description: ClientSecret is the OAuth 2.0 client secret + description: ClientID is the OAuth client ID for authentication type: string - external_token_header_name: - description: ExternalTokenHeaderName is the name of the custom header to - use when HeaderStrategy is "custom" + issuer: + description: |- + Issuer is the OAuth/OIDC issuer URL (e.g., https://accounts.google.com) + Used for OIDC discovery to find authorization and token endpoints type: string - header_strategy: + oauth_params: + additionalProperties: + type: string description: |- - HeaderStrategy determines how to inject the token - Valid values: HeaderStrategyReplace (default), HeaderStrategyCustom + OAuthParams contains additional OAuth parameters to include in the authorization request + These are server-specific parameters like "prompt", "response_mode", etc. + type: object + resource: + description: Resource is the OAuth 2.0 resource indicator (RFC 8707) type: string scopes: - description: Scopes is the list of scopes to request for the exchanged token + description: |- + Scopes are the OAuth scopes to request + If not specified, defaults to ["openid", "profile", "email"] for OIDC items: type: string type: array uniqueItems: false - subject_token_type: - description: |- - SubjectTokenType specifies the type of the subject token being exchanged. - Common values: tokenTypeAccessToken (default), tokenTypeIDToken, tokenTypeJWT. - If empty, defaults to tokenTypeAccessToken. - type: string token_url: - description: TokenURL is the OAuth 2.0 token endpoint URL - type: string - type: object - types.EnvVar: - properties: - default: description: |- - Default is the value to use if the environment variable is not explicitly provided - Only used for non-required variables - type: string - description: - description: Description is a human-readable explanation of the variable's - purpose - type: string - name: - description: Name is the environment variable name (e.g., API_KEY) + TokenURL is the OAuth token endpoint URL + Used for non-OIDC OAuth flows when issuer is not provided type: string - required: - description: |- - Required indicates whether this environment variable must be provided - If true and not provided via command line or secrets, the user will be prompted for a value - type: boolean - secret: + use_pkce: description: |- - Secret indicates whether this environment variable contains sensitive information - If true, the value will be stored as a secret rather than as a plain environment variable + UsePKCE indicates whether to use PKCE for the OAuth flow + Defaults to true for enhanced security type: boolean type: object - types.Group: - properties: - description: - description: Description is a human-readable description of the group's - purpose and functionality - type: string - name: - description: Name is the identifier for the group, used when referencing - the group in commands - type: string - remote_servers: - additionalProperties: - $ref: '#/components/schemas/types.RemoteServerMetadata' - description: RemoteServers is a map of server names to their corresponding - remote server definitions within this group - type: object - servers: - additionalProperties: - $ref: '#/components/schemas/types.ImageMetadata' - description: Servers is a map of server names to their corresponding server - definitions within this group - type: object - type: object - types.Header: + registry.Provenance: + description: Provenance contains verification and signing metadata properties: - choices: - description: Choices provides a list of valid values for the header (optional) - items: - type: string - type: array - uniqueItems: false - default: - description: |- - Default is the value to use if the header is not explicitly provided - Only used for non-required headers - type: string - description: - description: Description is a human-readable explanation of the header's - purpose + attestation: + $ref: '#/components/schemas/registry.VerifiedAttestation' + cert_issuer: type: string - name: - description: Name is the header name (e.g., X-API-Key, Authorization) + repository_ref: + type: string + repository_uri: + type: string + runner_environment: + type: string + signer_identity: + type: string + sigstore_url: type: string - required: - description: |- - Required indicates whether this header must be provided - If true and not provided via command line or secrets, the user will be prompted for a value - type: boolean - secret: - description: |- - Secret indicates whether this header contains sensitive information - If true, the value will be stored as a secret rather than as plain text - type: boolean type: object - types.ImageMetadata: - description: Container server details (if it's a container server) + registry.Registry: + description: Full registry data properties: - args: - description: |- - Args are the default command-line arguments to pass to the MCP server container. - These arguments will be used only if no command-line arguments are provided by the user. - If the user provides arguments, they will override these defaults. + groups: + description: Groups is a slice of group definitions containing related MCP + servers items: - type: string + $ref: '#/components/schemas/registry.Group' type: array uniqueItems: false + last_updated: + description: LastUpdated is the timestamp when the registry was last updated, + in RFC3339 format + type: string + remote_servers: + additionalProperties: + $ref: '#/components/schemas/registry.RemoteServerMetadata' + description: |- + RemoteServers is a map of server names to their corresponding remote server definitions + These are MCP servers accessed via HTTP/HTTPS using the thv proxy command + type: object + servers: + additionalProperties: + $ref: '#/components/schemas/registry.ImageMetadata' + description: Servers is a map of server names to their corresponding server + definitions + type: object + version: + description: Version is the schema version of the registry + type: string + type: object + registry.RemoteServerMetadata: + description: Remote server details (if it's a remote server) + properties: custom_metadata: additionalProperties: {} description: CustomMetadata allows for additional user-defined metadata @@ -776,34 +630,31 @@ components: description: Description is a human-readable description of the server's purpose and functionality type: string - docker_tags: - description: DockerTags lists the available Docker tags for this server - image + env_vars: + description: |- + EnvVars defines environment variables that can be passed to configure the client + These might be needed for client-side configuration when connecting to the remote server items: - type: string + $ref: '#/components/schemas/registry.EnvVar' type: array uniqueItems: false - env_vars: - description: EnvVars defines environment variables that can be passed to - the server + headers: + description: |- + Headers defines HTTP headers that can be passed to the remote server for authentication + These are used with the thv proxy command's authentication features items: - $ref: '#/components/schemas/types.EnvVar' + $ref: '#/components/schemas/registry.Header' type: array uniqueItems: false - image: - description: Image is the Docker image reference for the MCP server - type: string metadata: - $ref: '#/components/schemas/types.Metadata' + $ref: '#/components/schemas/registry.Metadata' name: description: |- Name is the identifier for the MCP server, used when referencing the server in commands If not provided, it will be auto-generated from the registry key type: string - permissions: - $ref: '#/components/schemas/permissions.Profile' - provenance: - $ref: '#/components/schemas/types.Provenance' + oauth_config: + $ref: '#/components/schemas/registry.OAuthConfig' repository_url: description: RepositoryURL is the URL to the source code repository for the server @@ -819,10 +670,6 @@ components: type: string type: array uniqueItems: false - target_port: - description: TargetPort is the port for the container to expose (only applicable - to SSE and Streamable HTTP transports) - type: integer tier: description: Tier represents the tier classification level of the server, e.g., "Official" or "Community" @@ -839,212 +686,371 @@ components: For containers: stdio, sse, or streamable-http For remote servers: sse or streamable-http (stdio not supported) type: string + url: + description: URL is the endpoint URL for the remote MCP server (e.g., https://api.example.com/mcp) + type: string type: object - types.Metadata: - description: Metadata contains additional information about the server such - as popularity metrics + registry.VerifiedAttestation: properties: - last_updated: - description: LastUpdated is the timestamp when the server was last updated, - in RFC3339 format + predicate: {} + predicate_type: type: string - pulls: - description: Pulls indicates how many times the server image has been downloaded - type: integer - stars: - description: Stars represents the popularity rating or number of stars for - the server - type: integer type: object - types.MiddlewareConfig: + remote.Config: + description: RemoteAuthConfig contains OAuth configuration for remote MCP servers properties: - parameters: - description: |- - Parameters is a JSON object containing the middleware parameters. - It is stored as a raw message to allow flexible parameter types. + authorize_url: + type: string + callback_port: + type: integer + client_id: + type: string + client_secret: + type: string + client_secret_file: + type: string + env_vars: + description: Environment variables for the client + items: + $ref: '#/components/schemas/registry.EnvVar' + type: array + uniqueItems: false + headers: + description: Headers for HTTP requests + items: + $ref: '#/components/schemas/registry.Header' + type: array + uniqueItems: false + issuer: + description: OAuth endpoint configuration (from registry) + type: string + oauth_params: + additionalProperties: + type: string + description: OAuth parameters for server-specific customization type: object - type: - description: Type is a string representing the middleware type. + resource: + description: Resource is the OAuth 2.0 resource indicator (RFC 8707). + type: string + scopes: + items: + type: string + type: array + uniqueItems: false + skip_browser: + type: boolean + timeout: + example: 5m + type: string + token_url: type: string + use_pkce: + type: boolean type: object - types.OAuthConfig: - description: |- - OAuthConfig provides OAuth/OIDC configuration for authentication to the remote server - Used with the thv proxy command's --remote-auth flags + runner.RunConfig: properties: - authorize_url: + audit_config: + $ref: '#/components/schemas/audit.Config' + audit_config_path: + description: AuditConfigPath is the path to the audit configuration file + type: string + authz_config: + $ref: '#/components/schemas/authz.Config' + authz_config_path: + description: AuthzConfigPath is the path to the authorization configuration + file + type: string + base_name: + description: BaseName is the base name used for the container (without prefixes) + type: string + cmd_args: + description: CmdArgs are the arguments to pass to the container + items: + type: string + type: array + uniqueItems: false + container_labels: + additionalProperties: + type: string + description: ContainerLabels are the labels to apply to the container + type: object + container_name: + description: ContainerName is the name of the container + type: string + debug: + description: Debug indicates whether debug mode is enabled + type: boolean + env_file_dir: + description: EnvFileDir is the directory path to load environment files + from + type: string + env_vars: + additionalProperties: + type: string + description: EnvVars are the parsed environment variables as key-value pairs + type: object + group: + description: Group is the name of the group this workload belongs to, if + any + type: string + host: + description: Host is the host for the HTTP proxy + type: string + ignore_config: + $ref: '#/components/schemas/ignore.Config' + image: + description: Image is the Docker image to run + type: string + isolate_network: + description: IsolateNetwork indicates whether to isolate the network for + the container + type: boolean + jwks_auth_token_file: + description: JWKSAuthTokenFile is the path to file containing auth token + for JWKS/OIDC requests + type: string + k8s_pod_template_patch: description: |- - AuthorizeURL is the OAuth authorization endpoint URL - Used for non-OIDC OAuth flows when issuer is not provided + K8sPodTemplatePatch is a JSON string to patch the Kubernetes pod template + Only applicable when using Kubernetes runtime type: string - callback_port: + middleware_configs: description: |- - CallbackPort is the specific port to use for the OAuth callback server - If not specified, a random available port will be used + MiddlewareConfigs contains the list of middleware to apply to the transport + and the configuration for each middleware. + items: + $ref: '#/components/schemas/types.MiddlewareConfig' + type: array + uniqueItems: false + name: + description: Name is the name of the MCP server + type: string + oidc_config: + $ref: '#/components/schemas/auth.TokenValidatorConfig' + permission_profile: + $ref: '#/components/schemas/permissions.Profile' + permission_profile_name_or_path: + description: PermissionProfileNameOrPath is the name or path of the permission + profile + type: string + port: + description: Port is the port for the HTTP proxy to listen on (host port) type: integer - client_id: - description: ClientID is the OAuth client ID for authentication + proxy_mode: + $ref: '#/components/schemas/types.ProxyMode' + remote_auth_config: + $ref: '#/components/schemas/remote.Config' + remote_url: + description: RemoteURL is the URL of the remote MCP server (if running remotely) type: string - issuer: + schema_version: + description: SchemaVersion is the version of the RunConfig schema + type: string + secrets: description: |- - Issuer is the OAuth/OIDC issuer URL (e.g., https://accounts.google.com) - Used for OIDC discovery to find authorization and token endpoints + Secrets are the secret parameters to pass to the container + Format: ",target=" + items: + type: string + type: array + uniqueItems: false + target_host: + description: TargetHost is the host to forward traffic to (only applicable + to SSE transport) + type: string + target_port: + description: TargetPort is the port for the container to expose (only applicable + to SSE transport) + type: integer + telemetry_config: + $ref: '#/components/schemas/telemetry.Config' + thv_ca_bundle: + description: ThvCABundle is the path to the CA certificate bundle for ToolHive + HTTP operations type: string - oauth_params: - additionalProperties: + token_exchange_config: + $ref: '#/components/schemas/tokenexchange.Config' + tools_filter: + description: ToolsFilter is the list of tools to filter + items: type: string - description: |- - OAuthParams contains additional OAuth parameters to include in the authorization request - These are server-specific parameters like "prompt", "response_mode", etc. + type: array + uniqueItems: false + tools_override: + additionalProperties: + $ref: '#/components/schemas/runner.ToolOverride' + description: ToolsOverride is a map from an actual tool to its overridden + name and/or description type: object - resource: - description: Resource is the OAuth 2.0 resource indicator (RFC 8707) + transport: + description: Transport is the transport mode (stdio, sse, or streamable-http) type: string - scopes: + x-enum-varnames: + - TransportTypeStdio + - TransportTypeSSE + - TransportTypeStreamableHTTP + - TransportTypeInspector + trust_proxy_headers: + description: TrustProxyHeaders indicates whether to trust X-Forwarded-* + headers from reverse proxies + type: boolean + volumes: description: |- - Scopes are the OAuth scopes to request - If not specified, defaults to ["openid", "profile", "email"] for OIDC + Volumes are the directory mounts to pass to the container + Format: "host-path:container-path[:ro]" items: type: string type: array uniqueItems: false - token_url: - description: |- - TokenURL is the OAuth token endpoint URL - Used for non-OIDC OAuth flows when issuer is not provided - type: string - use_pkce: - description: |- - UsePKCE indicates whether to use PKCE for the OAuth flow - Defaults to true for enhanced security - type: boolean type: object - types.Provenance: - description: Provenance contains verification and signing metadata + runner.ToolOverride: properties: - attestation: - $ref: '#/components/schemas/types.VerifiedAttestation' - cert_issuer: - type: string - repository_ref: - type: string - repository_uri: - type: string - runner_environment: - type: string - signer_identity: + description: + description: Description is the redefined description of the tool type: string - sigstore_url: + name: + description: Name is the redefined name of the tool type: string type: object - types.ProxyMode: - description: ProxyMode is the proxy mode for stdio transport ("sse" or "streamable-http") + runtime.WorkloadStatus: + description: Status is the current status of the workload. type: string x-enum-varnames: - - ProxyModeSSE - - ProxyModeStreamableHTTP - types.Registry: - description: Full registry data + - WorkloadStatusRunning + - WorkloadStatusStopped + - WorkloadStatusError + - WorkloadStatusStarting + - WorkloadStatusStopping + - WorkloadStatusUnhealthy + - WorkloadStatusRemoving + - WorkloadStatusUnknown + - WorkloadStatusUnauthenticated + secrets.SecretParameter: properties: - groups: - description: Groups is a slice of group definitions containing related MCP - servers - items: - $ref: '#/components/schemas/types.Group' - type: array - uniqueItems: false - last_updated: - description: LastUpdated is the timestamp when the registry was last updated, - in RFC3339 format + name: type: string - remote_servers: - additionalProperties: - $ref: '#/components/schemas/types.RemoteServerMetadata' - description: |- - RemoteServers is a map of server names to their corresponding remote server definitions - These are MCP servers accessed via HTTP/HTTPS using the thv proxy command - type: object - servers: - additionalProperties: - $ref: '#/components/schemas/types.ImageMetadata' - description: Servers is a map of server names to their corresponding server - definitions - type: object - version: - description: Version is the schema version of the registry + target: type: string type: object - types.RemoteServerMetadata: - description: Remote server details (if it's a remote server) + telemetry.Config: + description: TelemetryConfig contains the OpenTelemetry configuration properties: - custom_metadata: - additionalProperties: {} - description: CustomMetadata allows for additional user-defined metadata + customAttributes: + additionalProperties: + type: string + description: |- + CustomAttributes contains custom resource attributes to be added to all telemetry signals. + These are parsed from CLI flags (--otel-custom-attributes) or environment variables + (OTEL_RESOURCE_ATTRIBUTES) as key=value pairs. + We use map[string]string for proper JSON serialization instead of []attribute.KeyValue + which doesn't marshal/unmarshal correctly. type: object - description: - description: Description is a human-readable description of the server's - purpose and functionality + enablePrometheusMetricsPath: + description: |- + EnablePrometheusMetricsPath controls whether to expose Prometheus-style /metrics endpoint + The metrics are served on the main transport port at /metrics + This is separate from OTLP metrics which are sent to the Endpoint + type: boolean + endpoint: + description: Endpoint is the OTLP endpoint URL type: string - env_vars: + environmentVariables: description: |- - EnvVars defines environment variables that can be passed to configure the client - These might be needed for client-side configuration when connecting to the remote server + EnvironmentVariables is a list of environment variable names that should be + included in telemetry spans as attributes. Only variables in this list will + be read from the host machine and included in spans for observability. + Example: []string{"NODE_ENV", "DEPLOYMENT_ENV", "SERVICE_VERSION"} items: - $ref: '#/components/schemas/types.EnvVar' + type: string type: array uniqueItems: false headers: + additionalProperties: + type: string + description: Headers contains authentication headers for the OTLP endpoint + type: object + insecure: + description: Insecure indicates whether to use HTTP instead of HTTPS for + the OTLP endpoint + type: boolean + metricsEnabled: description: |- - Headers defines HTTP headers that can be passed to the remote server for authentication - These are used with the thv proxy command's authentication features - items: - $ref: '#/components/schemas/types.Header' - type: array - uniqueItems: false - metadata: - $ref: '#/components/schemas/types.Metadata' - name: + MetricsEnabled controls whether OTLP metrics are enabled + When false, OTLP metrics are not sent even if an endpoint is configured + This is independent of EnablePrometheusMetricsPath + type: boolean + samplingRate: description: |- - Name is the identifier for the MCP server, used when referencing the server in commands - If not provided, it will be auto-generated from the registry key + SamplingRate is the trace sampling rate (0.0-1.0) + Only used when TracingEnabled is true + type: number + serviceName: + description: ServiceName is the service name for telemetry type: string - oauth_config: - $ref: '#/components/schemas/types.OAuthConfig' - repository_url: - description: RepositoryURL is the URL to the source code repository for - the server + serviceVersion: + description: ServiceVersion is the service version for telemetry type: string - status: - description: Status indicates whether the server is currently active or - deprecated + tracingEnabled: + description: |- + TracingEnabled controls whether distributed tracing is enabled + When false, no tracer provider is created even if an endpoint is configured + type: boolean + type: object + tokenexchange.Config: + description: TokenExchangeConfig contains token exchange configuration for external + authentication + properties: + audience: + description: Audience is the target audience for the exchanged token type: string - tags: - description: Tags are categorization labels for the server to aid in discovery - and filtering - items: - type: string - type: array - uniqueItems: false - tier: - description: Tier represents the tier classification level of the server, - e.g., "Official" or "Community" + client_id: + description: ClientID is the OAuth 2.0 client identifier type: string - tools: - description: Tools is a list of tool names provided by this MCP server + client_secret: + description: ClientSecret is the OAuth 2.0 client secret + type: string + external_token_header_name: + description: ExternalTokenHeaderName is the name of the custom header to + use when HeaderStrategy is "custom" + type: string + header_strategy: + description: |- + HeaderStrategy determines how to inject the token + Valid values: HeaderStrategyReplace (default), HeaderStrategyCustom + type: string + scopes: + description: Scopes is the list of scopes to request for the exchanged token items: type: string type: array uniqueItems: false - transport: + subject_token_type: description: |- - Transport defines the communication protocol for the server - For containers: stdio, sse, or streamable-http - For remote servers: sse or streamable-http (stdio not supported) + SubjectTokenType specifies the type of the subject token being exchanged. + Common values: tokenTypeAccessToken (default), tokenTypeIDToken, tokenTypeJWT. + If empty, defaults to tokenTypeAccessToken. type: string - url: - description: URL is the endpoint URL for the remote MCP server (e.g., https://api.example.com/mcp) + token_url: + description: TokenURL is the OAuth 2.0 token endpoint URL + type: string + type: object + types.MiddlewareConfig: + properties: + parameters: + description: |- + Parameters is a JSON object containing the middleware parameters. + It is stored as a raw message to allow flexible parameter types. + type: object + type: + description: Type is a string representing the middleware type. type: string type: object + types.ProxyMode: + description: ProxyMode is the proxy mode for stdio transport ("sse" or "streamable-http") + type: string + x-enum-varnames: + - ProxyModeSSE + - ProxyModeStreamableHTTP types.TransportType: description: TransportType is the type of transport used for this workload. type: string @@ -1053,12 +1059,6 @@ components: - TransportTypeSSE - TransportTypeStreamableHTTP - TransportTypeInspector - types.VerifiedAttestation: - properties: - predicate: {} - predicate_type: - type: string - type: object v1.RegistryType: description: Type of registry (file, url, or default) type: string @@ -1249,7 +1249,7 @@ components: type: string headers: items: - $ref: '#/components/schemas/types.Header' + $ref: '#/components/schemas/registry.Header' type: array uniqueItems: false host: @@ -1353,7 +1353,7 @@ components: description: Name of the registry type: string registry: - $ref: '#/components/schemas/types.Registry' + $ref: '#/components/schemas/registry.Registry' server_count: description: Number of servers in the registry type: integer @@ -1392,9 +1392,9 @@ components: description: Indicates if this is a remote server type: boolean remote_server: - $ref: '#/components/schemas/types.RemoteServerMetadata' + $ref: '#/components/schemas/registry.RemoteServerMetadata' server: - $ref: '#/components/schemas/types.ImageMetadata' + $ref: '#/components/schemas/registry.ImageMetadata' type: object v1.groupListResponse: properties: @@ -1421,13 +1421,13 @@ components: remote_servers: description: List of remote servers in the registry (if any) items: - $ref: '#/components/schemas/types.RemoteServerMetadata' + $ref: '#/components/schemas/registry.RemoteServerMetadata' type: array uniqueItems: false servers: description: List of container servers in the registry items: - $ref: '#/components/schemas/types.ImageMetadata' + $ref: '#/components/schemas/registry.ImageMetadata' type: array uniqueItems: false type: object @@ -1612,7 +1612,7 @@ components: type: string headers: items: - $ref: '#/components/schemas/types.Header' + $ref: '#/components/schemas/registry.Header' type: array uniqueItems: false host: diff --git a/pkg/api/v1/registry.go b/pkg/api/v1/registry.go index faa42e139..35d5c2200 100644 --- a/pkg/api/v1/registry.go +++ b/pkg/api/v1/registry.go @@ -9,8 +9,8 @@ import ( "github.com/stacklok/toolhive/pkg/config" "github.com/stacklok/toolhive/pkg/logger" - "github.com/stacklok/toolhive/pkg/registry" - "github.com/stacklok/toolhive/pkg/registry/types" + regpkg "github.com/stacklok/toolhive/pkg/registry" + "github.com/stacklok/toolhive/pkg/registry/registry" ) const ( @@ -59,8 +59,8 @@ func getRegistryInfoWithProvider(configProvider config.Provider) (RegistryType, } // getCurrentProvider returns the current registry provider using the injected config -func (rr *RegistryRoutes) getCurrentProvider(w http.ResponseWriter) (registry.Provider, bool) { - provider, err := registry.GetDefaultProviderWithConfig(rr.configProvider) +func (rr *RegistryRoutes) getCurrentProvider(w http.ResponseWriter) (regpkg.Provider, bool) { + provider, err := regpkg.GetDefaultProviderWithConfig(rr.configProvider) if err != nil { http.Error(w, "Failed to get registry provider", http.StatusInternalServerError) logger.Errorf("Failed to get registry provider: %v", err) @@ -256,7 +256,7 @@ func (rr *RegistryRoutes) updateRegistry(w http.ResponseWriter, r *http.Request) } // Reset the default provider to pick up configuration changes - registry.ResetDefaultProvider() + regpkg.ResetDefaultProvider() response := UpdateRegistryResponse{ Message: message, @@ -401,8 +401,8 @@ func (rr *RegistryRoutes) listServers(w http.ResponseWriter, r *http.Request) { // Build response with both container and remote servers response := listServersResponse{ - Servers: make([]*types.ImageMetadata, 0, len(reg.Servers)), - RemoteServers: make([]*types.RemoteServerMetadata, 0, len(reg.RemoteServers)), + Servers: make([]*registry.ImageMetadata, 0, len(reg.Servers)), + RemoteServers: make([]*registry.RemoteServerMetadata, 0, len(reg.RemoteServers)), } // Add container servers @@ -460,14 +460,14 @@ func (rr *RegistryRoutes) getServer(w http.ResponseWriter, r *http.Request) { // Build response based on server type var response getServerResponse if server.IsRemote() { - if remote, ok := server.(*types.RemoteServerMetadata); ok { + if remote, ok := server.(*registry.RemoteServerMetadata); ok { response = getServerResponse{ RemoteServer: remote, IsRemote: true, } } } else { - if img, ok := server.(*types.ImageMetadata); ok { + if img, ok := server.(*registry.ImageMetadata); ok { response = getServerResponse{ Server: img, IsRemote: false, @@ -528,7 +528,7 @@ type getRegistryResponse struct { // Source of the registry (URL, file path, or empty string for built-in) Source string `json:"source"` // Full registry data - Registry *types.Registry `json:"registry"` + Registry *registry.Registry `json:"registry"` } // listServersResponse represents the response for listing servers in a registry @@ -536,9 +536,9 @@ type getRegistryResponse struct { // @Description Response containing a list of servers type listServersResponse struct { // List of container servers in the registry - Servers []*types.ImageMetadata `json:"servers"` + Servers []*registry.ImageMetadata `json:"servers"` // List of remote servers in the registry (if any) - RemoteServers []*types.RemoteServerMetadata `json:"remote_servers,omitempty"` + RemoteServers []*registry.RemoteServerMetadata `json:"remote_servers,omitempty"` } // getServerResponse represents the response for getting a server from a registry @@ -546,9 +546,9 @@ type listServersResponse struct { // @Description Response containing server details type getServerResponse struct { // Container server details (if it's a container server) - Server *types.ImageMetadata `json:"server,omitempty"` + Server *registry.ImageMetadata `json:"server,omitempty"` // Remote server details (if it's a remote server) - RemoteServer *types.RemoteServerMetadata `json:"remote_server,omitempty"` + RemoteServer *registry.RemoteServerMetadata `json:"remote_server,omitempty"` // Indicates if this is a remote server IsRemote bool `json:"is_remote"` } diff --git a/pkg/api/v1/workload_service.go b/pkg/api/v1/workload_service.go index 92b48dd9a..2b73456b4 100644 --- a/pkg/api/v1/workload_service.go +++ b/pkg/api/v1/workload_service.go @@ -10,7 +10,7 @@ import ( "github.com/stacklok/toolhive/pkg/container/runtime" "github.com/stacklok/toolhive/pkg/groups" "github.com/stacklok/toolhive/pkg/logger" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner" "github.com/stacklok/toolhive/pkg/runner/retriever" "github.com/stacklok/toolhive/pkg/secrets" diff --git a/pkg/api/v1/workload_types.go b/pkg/api/v1/workload_types.go index fbbfbdab1..de1a8ed22 100644 --- a/pkg/api/v1/workload_types.go +++ b/pkg/api/v1/workload_types.go @@ -6,7 +6,7 @@ import ( "github.com/stacklok/toolhive/pkg/container/runtime" "github.com/stacklok/toolhive/pkg/core" "github.com/stacklok/toolhive/pkg/permissions" - "github.com/stacklok/toolhive/pkg/registry/types" + "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner" "github.com/stacklok/toolhive/pkg/secrets" ) @@ -69,9 +69,9 @@ type updateRequest struct { Group string `json:"group,omitempty"` // Remote server specific fields - URL string `json:"url,omitempty"` - OAuthConfig remoteOAuthConfig `json:"oauth_config,omitempty"` - Headers []*types.Header `json:"headers,omitempty"` + URL string `json:"url,omitempty"` + OAuthConfig remoteOAuthConfig `json:"oauth_config,omitempty"` + Headers []*registry.Header `json:"headers,omitempty"` } // toolOverride represents a tool override @@ -201,7 +201,7 @@ func runConfigToCreateRequest(runConfig *runner.RunConfig) *createRequest { // Get remote OAuth config from RunConfig var oAuthConfig remoteOAuthConfig - var headers []*types.Header + var headers []*registry.Header if runConfig.RemoteAuthConfig != nil { // Parse ClientSecret from CLI format to SecretParameter (for details API) var clientSecretParam *secrets.SecretParameter diff --git a/pkg/api/v1/workloads_test.go b/pkg/api/v1/workloads_test.go index 8054bf6a9..38adf2d48 100644 --- a/pkg/api/v1/workloads_test.go +++ b/pkg/api/v1/workloads_test.go @@ -19,7 +19,7 @@ import ( "github.com/stacklok/toolhive/pkg/core" groupsmocks "github.com/stacklok/toolhive/pkg/groups/mocks" "github.com/stacklok/toolhive/pkg/logger" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner" "github.com/stacklok/toolhive/pkg/runner/retriever" workloadsmocks "github.com/stacklok/toolhive/pkg/workloads/mocks" diff --git a/pkg/auth/remote/config.go b/pkg/auth/remote/config.go index 8f321873f..9ea6e5911 100644 --- a/pkg/auth/remote/config.go +++ b/pkg/auth/remote/config.go @@ -8,7 +8,7 @@ import ( "time" "github.com/stacklok/toolhive/pkg/logger" - "github.com/stacklok/toolhive/pkg/registry/types" + "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/validation" ) @@ -33,10 +33,10 @@ type Config struct { TokenURL string `json:"token_url,omitempty" yaml:"token_url,omitempty"` // Headers for HTTP requests - Headers []*types.Header `json:"headers,omitempty" yaml:"headers,omitempty"` + Headers []*registry.Header `json:"headers,omitempty" yaml:"headers,omitempty"` // Environment variables for the client - EnvVars []*types.EnvVar `json:"env_vars,omitempty" yaml:"env_vars,omitempty"` + EnvVars []*registry.EnvVar `json:"env_vars,omitempty" yaml:"env_vars,omitempty"` // OAuth parameters for server-specific customization OAuthParams map[string]string `json:"oauth_params,omitempty" yaml:"oauth_params,omitempty"` @@ -56,20 +56,20 @@ func (r *Config) UnmarshalJSON(data []byte) error { if _, isOld := raw["ClientID"]; isOld { // Unmarshal using old PascalCase format var oldFormat struct { - ClientID string `json:"ClientID,omitempty"` - ClientSecret string `json:"ClientSecret,omitempty"` - ClientSecretFile string `json:"ClientSecretFile,omitempty"` - Scopes []string `json:"Scopes,omitempty"` - SkipBrowser bool `json:"SkipBrowser,omitempty"` - Timeout time.Duration `json:"Timeout,omitempty"` - CallbackPort int `json:"CallbackPort,omitempty"` - UsePKCE bool `json:"UsePKCE,omitempty"` - Issuer string `json:"Issuer,omitempty"` - AuthorizeURL string `json:"AuthorizeURL,omitempty"` - TokenURL string `json:"TokenURL,omitempty"` - Headers []*types.Header `json:"Headers,omitempty"` - EnvVars []*types.EnvVar `json:"EnvVars,omitempty"` - OAuthParams map[string]string `json:"OAuthParams,omitempty"` + ClientID string `json:"ClientID,omitempty"` + ClientSecret string `json:"ClientSecret,omitempty"` + ClientSecretFile string `json:"ClientSecretFile,omitempty"` + Scopes []string `json:"Scopes,omitempty"` + SkipBrowser bool `json:"SkipBrowser,omitempty"` + Timeout time.Duration `json:"Timeout,omitempty"` + CallbackPort int `json:"CallbackPort,omitempty"` + UsePKCE bool `json:"UsePKCE,omitempty"` + Issuer string `json:"Issuer,omitempty"` + AuthorizeURL string `json:"AuthorizeURL,omitempty"` + TokenURL string `json:"TokenURL,omitempty"` + Headers []*registry.Header `json:"Headers,omitempty"` + EnvVars []*registry.EnvVar `json:"EnvVars,omitempty"` + OAuthParams map[string]string `json:"OAuthParams,omitempty"` } if err := json.Unmarshal(data, &oldFormat); err != nil { diff --git a/pkg/container/verifier/verifier.go b/pkg/container/verifier/verifier.go index 0fe011294..431e77225 100644 --- a/pkg/container/verifier/verifier.go +++ b/pkg/container/verifier/verifier.go @@ -13,7 +13,7 @@ import ( "github.com/stacklok/toolhive/pkg/container/images" "github.com/stacklok/toolhive/pkg/logger" - "github.com/stacklok/toolhive/pkg/registry/types" + "github.com/stacklok/toolhive/pkg/registry/registry" ) const ( @@ -39,7 +39,7 @@ type Result struct { } // New creates a new Sigstore verifier -func New(serverInfo *types.ImageMetadata) (*Sigstore, error) { +func New(serverInfo *registry.ImageMetadata) (*Sigstore, error) { // Fail the verification early if the server information is not set if serverInfo == nil || serverInfo.Provenance == nil { return nil, ErrProvenanceServerInformationNotSet @@ -130,7 +130,7 @@ func getVerifiedResults( } // VerifyServer verifies the server information for the given image reference -func (s *Sigstore) VerifyServer(imageRef string, serverInfo *types.ImageMetadata) (bool, error) { +func (s *Sigstore) VerifyServer(imageRef string, serverInfo *registry.ImageMetadata) (bool, error) { // Get the verification results for the image reference results, err := s.GetVerificationResults(imageRef) if err != nil { @@ -153,7 +153,7 @@ func (s *Sigstore) VerifyServer(imageRef string, serverInfo *types.ImageMetadata return true, nil } -func isVerificationResultMatchingServerProvenance(r *verify.VerificationResult, p *types.Provenance) bool { +func isVerificationResultMatchingServerProvenance(r *verify.VerificationResult, p *registry.Provenance) bool { if r == nil || p == nil || r.Signature == nil || r.Signature.Certificate == nil { return false } @@ -175,7 +175,7 @@ func isVerificationResultMatchingServerProvenance(r *verify.VerificationResult, } // compareBaseProperties compares the base properties of the verification result and the server provenance -func compareBaseProperties(r *verify.VerificationResult, p *types.Provenance) bool { +func compareBaseProperties(r *verify.VerificationResult, p *registry.Provenance) bool { // Extract the signer identity from the certificate siIdentity, err := signerIdentityFromCertificate(r.Signature.Certificate) if err != nil { diff --git a/pkg/mcp/server/handler_mock_test.go b/pkg/mcp/server/handler_mock_test.go index 5c9213ae2..f36444d1d 100644 --- a/pkg/mcp/server/handler_mock_test.go +++ b/pkg/mcp/server/handler_mock_test.go @@ -12,7 +12,7 @@ import ( runtime "github.com/stacklok/toolhive/pkg/container/runtime" "github.com/stacklok/toolhive/pkg/core" registrymocks "github.com/stacklok/toolhive/pkg/registry/mocks" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" workloadsmocks "github.com/stacklok/toolhive/pkg/workloads/mocks" ) diff --git a/pkg/mcp/server/handler_test.go b/pkg/mcp/server/handler_test.go index 6388b6777..825fe73a9 100644 --- a/pkg/mcp/server/handler_test.go +++ b/pkg/mcp/server/handler_test.go @@ -7,7 +7,7 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/stretchr/testify/assert" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner" ) diff --git a/pkg/mcp/server/run_server.go b/pkg/mcp/server/run_server.go index 53eb55837..c3e89c28c 100644 --- a/pkg/mcp/server/run_server.go +++ b/pkg/mcp/server/run_server.go @@ -8,7 +8,7 @@ import ( "github.com/stacklok/toolhive/pkg/container" "github.com/stacklok/toolhive/pkg/logger" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner" "github.com/stacklok/toolhive/pkg/runner/retriever" transporttypes "github.com/stacklok/toolhive/pkg/transport/types" diff --git a/pkg/mcp/server/search_registry.go b/pkg/mcp/server/search_registry.go index 13bf5d726..5a78055b4 100644 --- a/pkg/mcp/server/search_registry.go +++ b/pkg/mcp/server/search_registry.go @@ -6,7 +6,7 @@ import ( "github.com/mark3labs/mcp-go/mcp" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // searchRegistryArgs holds the arguments for searching the registry diff --git a/pkg/registry/converters/converters_fixture_test.go b/pkg/registry/converters/converters_fixture_test.go index da982e152..c29e5f1fb 100644 --- a/pkg/registry/converters/converters_fixture_test.go +++ b/pkg/registry/converters/converters_fixture_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // TestConverters_Fixtures validates converter functions using JSON fixture files diff --git a/pkg/registry/converters/converters_test.go b/pkg/registry/converters/converters_test.go index 58e365699..1a69f6476 100644 --- a/pkg/registry/converters/converters_test.go +++ b/pkg/registry/converters/converters_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // Test Helpers diff --git a/pkg/registry/converters/envvar_extraction_test.go b/pkg/registry/converters/envvar_extraction_test.go index 43486bfad..9c7337369 100644 --- a/pkg/registry/converters/envvar_extraction_test.go +++ b/pkg/registry/converters/envvar_extraction_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // Test extracting environment variables from runtime arguments (-e flags) diff --git a/pkg/registry/converters/integration_test.go b/pkg/registry/converters/integration_test.go index e326c218f..4d716542d 100644 --- a/pkg/registry/converters/integration_test.go +++ b/pkg/registry/converters/integration_test.go @@ -11,7 +11,7 @@ import ( upstream "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/stretchr/testify/require" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // ToolHiveRegistry represents the structure of registry.json diff --git a/pkg/registry/converters/registry_converters.go b/pkg/registry/converters/registry_converters.go index 5200ba25b..da1990b96 100644 --- a/pkg/registry/converters/registry_converters.go +++ b/pkg/registry/converters/registry_converters.go @@ -6,7 +6,7 @@ import ( upstreamv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // NewUpstreamRegistryFromUpstreamServers creates a UpstreamRegistry from upstream ServerJSON array. diff --git a/pkg/registry/converters/registry_converters_test.go b/pkg/registry/converters/registry_converters_test.go index 168e5730b..8eba37b15 100644 --- a/pkg/registry/converters/registry_converters_test.go +++ b/pkg/registry/converters/registry_converters_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) func TestNewUpstreamRegistryFromToolhiveRegistry(t *testing.T) { diff --git a/pkg/registry/converters/toolhive_to_upstream.go b/pkg/registry/converters/toolhive_to_upstream.go index 2c747689f..03802aa44 100644 --- a/pkg/registry/converters/toolhive_to_upstream.go +++ b/pkg/registry/converters/toolhive_to_upstream.go @@ -16,12 +16,12 @@ import ( upstream "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" - "github.com/stacklok/toolhive/pkg/registry/types" + "github.com/stacklok/toolhive/pkg/registry/registry" ) // ImageMetadataToServerJSON converts toolhive ImageMetadata to an upstream ServerJSON // The name parameter is deprecated and should match imageMetadata.Name. It's kept for backward compatibility. -func ImageMetadataToServerJSON(name string, imageMetadata *types.ImageMetadata) (*upstream.ServerJSON, error) { +func ImageMetadataToServerJSON(name string, imageMetadata *registry.ImageMetadata) (*upstream.ServerJSON, error) { if imageMetadata == nil { return nil, fmt.Errorf("imageMetadata cannot be nil") } @@ -65,7 +65,7 @@ func ImageMetadataToServerJSON(name string, imageMetadata *types.ImageMetadata) // RemoteServerMetadataToServerJSON converts toolhive RemoteServerMetadata to an upstream ServerJSON // The name parameter is deprecated and should match remoteMetadata.Name. It's kept for backward compatibility. -func RemoteServerMetadataToServerJSON(name string, remoteMetadata *types.RemoteServerMetadata) (*upstream.ServerJSON, error) { +func RemoteServerMetadataToServerJSON(name string, remoteMetadata *registry.RemoteServerMetadata) (*upstream.ServerJSON, error) { if remoteMetadata == nil { return nil, fmt.Errorf("remoteMetadata cannot be nil") } @@ -108,7 +108,7 @@ func RemoteServerMetadataToServerJSON(name string, remoteMetadata *types.RemoteS } // createPackagesFromImageMetadata creates OCI Package entries from ImageMetadata -func createPackagesFromImageMetadata(imageMetadata *types.ImageMetadata) []model.Package { +func createPackagesFromImageMetadata(imageMetadata *registry.ImageMetadata) []model.Package { // Convert environment variables var envVars []model.KeyValueInput for _, envVar := range imageMetadata.EnvVars { @@ -158,7 +158,7 @@ func createPackagesFromImageMetadata(imageMetadata *types.ImageMetadata) []model } // createRemotesFromRemoteMetadata creates Transport entries from RemoteServerMetadata -func createRemotesFromRemoteMetadata(remoteMetadata *types.RemoteServerMetadata) []model.Transport { +func createRemotesFromRemoteMetadata(remoteMetadata *registry.RemoteServerMetadata) []model.Transport { // Convert headers var headers []model.KeyValueInput for _, header := range remoteMetadata.Headers { @@ -182,7 +182,7 @@ func createRemotesFromRemoteMetadata(remoteMetadata *types.RemoteServerMetadata) } // createImageExtensions creates publisher extensions map from ImageMetadata -func createImageExtensions(imageMetadata *types.ImageMetadata) map[string]interface{} { +func createImageExtensions(imageMetadata *registry.ImageMetadata) map[string]interface{} { extensions := make(map[string]interface{}) // Always include status @@ -246,7 +246,7 @@ func createImageExtensions(imageMetadata *types.ImageMetadata) map[string]interf } // createRemoteExtensions creates publisher extensions map from RemoteServerMetadata -func createRemoteExtensions(remoteMetadata *types.RemoteServerMetadata) map[string]interface{} { +func createRemoteExtensions(remoteMetadata *registry.RemoteServerMetadata) map[string]interface{} { extensions := make(map[string]interface{}) // Always include status diff --git a/pkg/registry/converters/upstream_to_toolhive.go b/pkg/registry/converters/upstream_to_toolhive.go index f3c65427e..88eef3099 100644 --- a/pkg/registry/converters/upstream_to_toolhive.go +++ b/pkg/registry/converters/upstream_to_toolhive.go @@ -12,7 +12,7 @@ import ( "github.com/modelcontextprotocol/registry/pkg/model" "github.com/stacklok/toolhive/pkg/permissions" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // ServerJSONToImageMetadata converts an upstream ServerJSON (with OCI packages) to toolhive ImageMetadata diff --git a/pkg/registry/mocks/mock_provider.go b/pkg/registry/mocks/mock_provider.go index 28c2b2491..80d6e3d09 100644 --- a/pkg/registry/mocks/mock_provider.go +++ b/pkg/registry/mocks/mock_provider.go @@ -12,7 +12,7 @@ package mocks import ( reflect "reflect" - types "github.com/stacklok/toolhive/pkg/registry/types" + registry "github.com/stacklok/toolhive/pkg/registry/registry" gomock "go.uber.org/mock/gomock" ) @@ -41,10 +41,10 @@ func (m *MockProvider) EXPECT() *MockProviderMockRecorder { } // GetImageServer mocks base method. -func (m *MockProvider) GetImageServer(name string) (*types.ImageMetadata, error) { +func (m *MockProvider) GetImageServer(name string) (*registry.ImageMetadata, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetImageServer", name) - ret0, _ := ret[0].(*types.ImageMetadata) + ret0, _ := ret[0].(*registry.ImageMetadata) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -56,10 +56,10 @@ func (mr *MockProviderMockRecorder) GetImageServer(name any) *gomock.Call { } // GetRegistry mocks base method. -func (m *MockProvider) GetRegistry() (*types.Registry, error) { +func (m *MockProvider) GetRegistry() (*registry.Registry, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetRegistry") - ret0, _ := ret[0].(*types.Registry) + ret0, _ := ret[0].(*registry.Registry) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -71,10 +71,10 @@ func (mr *MockProviderMockRecorder) GetRegistry() *gomock.Call { } // GetServer mocks base method. -func (m *MockProvider) GetServer(name string) (types.ServerMetadata, error) { +func (m *MockProvider) GetServer(name string) (registry.ServerMetadata, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetServer", name) - ret0, _ := ret[0].(types.ServerMetadata) + ret0, _ := ret[0].(registry.ServerMetadata) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -86,10 +86,10 @@ func (mr *MockProviderMockRecorder) GetServer(name any) *gomock.Call { } // ListImageServers mocks base method. -func (m *MockProvider) ListImageServers() ([]*types.ImageMetadata, error) { +func (m *MockProvider) ListImageServers() ([]*registry.ImageMetadata, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ListImageServers") - ret0, _ := ret[0].([]*types.ImageMetadata) + ret0, _ := ret[0].([]*registry.ImageMetadata) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -101,10 +101,10 @@ func (mr *MockProviderMockRecorder) ListImageServers() *gomock.Call { } // ListServers mocks base method. -func (m *MockProvider) ListServers() ([]types.ServerMetadata, error) { +func (m *MockProvider) ListServers() ([]registry.ServerMetadata, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ListServers") - ret0, _ := ret[0].([]types.ServerMetadata) + ret0, _ := ret[0].([]registry.ServerMetadata) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -116,10 +116,10 @@ func (mr *MockProviderMockRecorder) ListServers() *gomock.Call { } // SearchImageServers mocks base method. -func (m *MockProvider) SearchImageServers(query string) ([]*types.ImageMetadata, error) { +func (m *MockProvider) SearchImageServers(query string) ([]*registry.ImageMetadata, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SearchImageServers", query) - ret0, _ := ret[0].([]*types.ImageMetadata) + ret0, _ := ret[0].([]*registry.ImageMetadata) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -131,10 +131,10 @@ func (mr *MockProviderMockRecorder) SearchImageServers(query any) *gomock.Call { } // SearchServers mocks base method. -func (m *MockProvider) SearchServers(query string) ([]types.ServerMetadata, error) { +func (m *MockProvider) SearchServers(query string) ([]registry.ServerMetadata, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SearchServers", query) - ret0, _ := ret[0].([]types.ServerMetadata) + ret0, _ := ret[0].([]registry.ServerMetadata) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/pkg/registry/provider.go b/pkg/registry/provider.go index 9f708a5fc..7e408df16 100644 --- a/pkg/registry/provider.go +++ b/pkg/registry/provider.go @@ -1,6 +1,6 @@ package registry -import "github.com/stacklok/toolhive/pkg/registry/types" +import types "github.com/stacklok/toolhive/pkg/registry/registry" //go:generate mockgen -destination=mocks/mock_provider.go -package=mocks -source=provider.go Provider diff --git a/pkg/registry/provider_api.go b/pkg/registry/provider_api.go index ae3518e1f..5b6855df7 100644 --- a/pkg/registry/provider_api.go +++ b/pkg/registry/provider_api.go @@ -9,7 +9,7 @@ import ( "github.com/stacklok/toolhive/pkg/registry/api" "github.com/stacklok/toolhive/pkg/registry/converters" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // APIRegistryProvider provides registry data from an MCP Registry API endpoint diff --git a/pkg/registry/provider_base.go b/pkg/registry/provider_base.go index fcaa699b3..3f16062ec 100644 --- a/pkg/registry/provider_base.go +++ b/pkg/registry/provider_base.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // BaseProvider provides common implementation for registry providers diff --git a/pkg/registry/provider_cached.go b/pkg/registry/provider_cached.go index dab9e6c7a..59781fc9c 100644 --- a/pkg/registry/provider_cached.go +++ b/pkg/registry/provider_cached.go @@ -13,7 +13,7 @@ import ( "github.com/adrg/xdg" v0 "github.com/modelcontextprotocol/registry/pkg/api/v0" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) const ( diff --git a/pkg/registry/provider_local.go b/pkg/registry/provider_local.go index 2848e978d..afec68ce3 100644 --- a/pkg/registry/provider_local.go +++ b/pkg/registry/provider_local.go @@ -6,7 +6,7 @@ import ( "fmt" "os" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) //go:embed data/registry.json diff --git a/pkg/registry/provider_remote.go b/pkg/registry/provider_remote.go index 3d19a074d..1157e9f07 100644 --- a/pkg/registry/provider_remote.go +++ b/pkg/registry/provider_remote.go @@ -7,7 +7,7 @@ import ( "net/http" "github.com/stacklok/toolhive/pkg/networking" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // RemoteRegistryProvider provides registry data from a remote HTTP endpoint diff --git a/pkg/registry/provider_test.go b/pkg/registry/provider_test.go index 04e73155c..d079ac55a 100644 --- a/pkg/registry/provider_test.go +++ b/pkg/registry/provider_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stacklok/toolhive/pkg/config" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) func TestNewRegistryProvider(t *testing.T) { diff --git a/pkg/registry/types/registry_types.go b/pkg/registry/registry/registry_types.go similarity index 99% rename from pkg/registry/types/registry_types.go rename to pkg/registry/registry/registry_types.go index bf7d5fd86..454d8c943 100644 --- a/pkg/registry/types/registry_types.go +++ b/pkg/registry/registry/registry_types.go @@ -1,5 +1,5 @@ -// Package types contains the core type definitions for the MCP registry system. -package types +// Package registry contains the core type definitions for the MCP registry system. +package registry import ( "sort" diff --git a/pkg/registry/types/upstream_registry.go b/pkg/registry/registry/upstream_registry.go similarity index 97% rename from pkg/registry/types/upstream_registry.go rename to pkg/registry/registry/upstream_registry.go index 13ea928a2..8fbb2e214 100644 --- a/pkg/registry/types/upstream_registry.go +++ b/pkg/registry/registry/upstream_registry.go @@ -1,4 +1,4 @@ -package types +package registry import ( upstreamv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" diff --git a/pkg/registry/schema_validation_test.go b/pkg/registry/schema_validation_test.go index d52ea1c18..e6210e157 100644 --- a/pkg/registry/schema_validation_test.go +++ b/pkg/registry/schema_validation_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) // TestEmbeddedRegistrySchemaValidation validates that the embedded registry.json diff --git a/pkg/registry/types_test.go b/pkg/registry/types_test.go index f1ed5cd46..4132f2873 100644 --- a/pkg/registry/types_test.go +++ b/pkg/registry/types_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" ) func TestRegistryWithRemoteServers(t *testing.T) { diff --git a/pkg/runner/config_builder.go b/pkg/runner/config_builder.go index ab0e1355f..22791b9a7 100644 --- a/pkg/runner/config_builder.go +++ b/pkg/runner/config_builder.go @@ -18,7 +18,7 @@ import ( "github.com/stacklok/toolhive/pkg/logger" "github.com/stacklok/toolhive/pkg/mcp" "github.com/stacklok/toolhive/pkg/permissions" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/telemetry" "github.com/stacklok/toolhive/pkg/transport" "github.com/stacklok/toolhive/pkg/transport/types" diff --git a/pkg/runner/config_builder_test.go b/pkg/runner/config_builder_test.go index 3a7490390..4967bf1b9 100644 --- a/pkg/runner/config_builder_test.go +++ b/pkg/runner/config_builder_test.go @@ -14,7 +14,7 @@ import ( "github.com/stacklok/toolhive/pkg/logger" "github.com/stacklok/toolhive/pkg/mcp" "github.com/stacklok/toolhive/pkg/permissions" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/transport/types" ) diff --git a/pkg/runner/config_test.go b/pkg/runner/config_test.go index 3490a307b..a91b241ea 100644 --- a/pkg/runner/config_test.go +++ b/pkg/runner/config_test.go @@ -17,7 +17,7 @@ import ( "github.com/stacklok/toolhive/pkg/ignore" "github.com/stacklok/toolhive/pkg/logger" "github.com/stacklok/toolhive/pkg/permissions" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" secretsmocks "github.com/stacklok/toolhive/pkg/secrets/mocks" "github.com/stacklok/toolhive/pkg/telemetry" "github.com/stacklok/toolhive/pkg/transport/types" diff --git a/pkg/runner/env.go b/pkg/runner/env.go index 6f0d80d36..fb8b68558 100644 --- a/pkg/runner/env.go +++ b/pkg/runner/env.go @@ -10,7 +10,7 @@ import ( "github.com/stacklok/toolhive/pkg/config" "github.com/stacklok/toolhive/pkg/logger" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/secrets" ) @@ -23,7 +23,7 @@ type EnvVarValidator interface { // and returns the processed environment variables to be set. Validate( ctx context.Context, - metadata *regtypes.ImageMetadata, + metadata *registry.ImageMetadata, runConfig *RunConfig, suppliedEnvVars map[string]string, ) (map[string]string, error) @@ -38,7 +38,7 @@ type DetachedEnvVarValidator struct{} // and returns the processed environment variables to be set. func (*DetachedEnvVarValidator) Validate( _ context.Context, - metadata *regtypes.ImageMetadata, + metadata *registry.ImageMetadata, runConfig *RunConfig, suppliedEnvVars map[string]string, ) (map[string]string, error) { @@ -80,7 +80,7 @@ func NewCLIEnvVarValidator(configProvider config.Provider) *CLIEnvVarValidator { // and returns the processed environment variables to be set. func (v *CLIEnvVarValidator) Validate( ctx context.Context, - metadata *regtypes.ImageMetadata, + metadata *registry.ImageMetadata, runConfig *RunConfig, suppliedEnvVars map[string]string, ) (map[string]string, error) { @@ -152,7 +152,7 @@ func (v *CLIEnvVarValidator) Validate( } // promptForEnvironmentVariable prompts the user for an environment variable value -func promptForEnvironmentVariable(envVar *regtypes.EnvVar) (string, error) { +func promptForEnvironmentVariable(envVar *registry.EnvVar) (string, error) { var byteValue []byte var err error if envVar.Secret { @@ -182,7 +182,7 @@ func promptForEnvironmentVariable(envVar *regtypes.EnvVar) (string, error) { // addNewVariable adds an environment variable or secret to the appropriate list func addNewVariable( ctx context.Context, - envVar *regtypes.EnvVar, + envVar *registry.EnvVar, value string, secretsManager secrets.Provider, envVars *map[string]string, @@ -198,7 +198,7 @@ func addNewVariable( // addAsSecret stores the value as a secret and adds a secret reference func addAsSecret( ctx context.Context, - envVar *regtypes.EnvVar, + envVar *registry.EnvVar, value string, secretsManager secrets.Provider, secretsList *[]string, @@ -229,7 +229,7 @@ func addAsSecret( } // initializeSecretsManagerIfNeeded initializes the secrets manager if there are secret environment variables -func (v *CLIEnvVarValidator) initializeSecretsManagerIfNeeded(registryEnvVars []*regtypes.EnvVar) secrets.Provider { +func (v *CLIEnvVarValidator) initializeSecretsManagerIfNeeded(registryEnvVars []*registry.EnvVar) secrets.Provider { // Check if we have any secret environment variables hasSecrets := false for _, envVar := range registryEnvVars { @@ -319,7 +319,7 @@ func isSecretReferenceEnvVar(secret, envVarName string) bool { // addAsEnvironmentVariable adds the value as a regular environment variable func addAsEnvironmentVariable( - envVar *regtypes.EnvVar, + envVar *registry.EnvVar, value string, envVars *map[string]string, ) { diff --git a/pkg/runner/retriever/retriever.go b/pkg/runner/retriever/retriever.go index 598873bcc..c5e8dcc29 100644 --- a/pkg/runner/retriever/retriever.go +++ b/pkg/runner/retriever/retriever.go @@ -13,7 +13,7 @@ import ( "github.com/stacklok/toolhive/pkg/container/verifier" "github.com/stacklok/toolhive/pkg/logger" "github.com/stacklok/toolhive/pkg/registry" - "github.com/stacklok/toolhive/pkg/registry/types" + types "github.com/stacklok/toolhive/pkg/registry/registry" "github.com/stacklok/toolhive/pkg/runner" ) diff --git a/pkg/runner/retriever/retriever_test.go b/pkg/runner/retriever/retriever_test.go index b9382d74a..e0f6096e3 100644 --- a/pkg/runner/retriever/retriever_test.go +++ b/pkg/runner/retriever/retriever_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stacklok/toolhive/pkg/registry" - regtypes "github.com/stacklok/toolhive/pkg/registry/types" + regtypes "github.com/stacklok/toolhive/pkg/registry/registry" ) func TestGetMCPServer_WithGroup(t *testing.T) {