Documentation
¶
Overview ¶
attach.go — the exported boot-time MCP server attachment helper (Phase 110d, D-197; absorbs cmd/harbor's attachDevMCPServer from Phase 83g / D-150 INCLUDING the Phase 26b config→ToolPolicy projection that the devstack mirror had silently dropped).
Attach wires ONE configured MCP server into a running stack: it projects the operator-facing policy YAML onto the driver's runtime ToolPolicy fields, spawns the transport, opens the MCP session, discovers tools, registers each ToolDescriptor on the tool catalog, surfaces the live Provider on the Registry (with its configured per-server policy + seeded discovery stats), and threads the Provider's Close into the caller's closer chain so stack teardown drains the subprocess. Fail-loud on every step: a misconfigured / unreachable MCP server must not boot silently (CLAUDE.md §13).
Package mcp is Harbor's Model Context Protocol (MCP) southbound driver. It implements `tools.ToolProvider` against a remote MCP server, exposing the server's tools / resources / prompts as Harbor `Tool` entries (RFC §6.4). Three wire transports are supported (stdio, SSE, streamable-HTTP) with auto-detect.
Concurrent reuse (D-025): a constructed *Provider is safe to share across N concurrent goroutines after Connect returns. All per-call state lives on the goroutine stack + the request `ctx`; descriptor fields are immutable after Discover.
Identity (RFC §4): the (tenant, user, session) triple is forwarded to the remote MCP server in the request's `_meta` map so trust signals flow across the seam.
Reliability shell (D-024): every Invoke runs inside `tools.RunWithPolicy` so timeout / retry / classifier behaviour is identical to the in-process driver.
Index ¶
- Constants
- Variables
- func Attach(ctx context.Context, ms config.MCPServerConfig, deps AttachDeps) error
- func IsValidTransportMode(s string) bool
- func ProjectToolPolicies(ms config.MCPServerConfig) (tools.ToolPolicy, map[string]tools.ToolPolicy, error)
- type AttachDeps
- type AudioRef
- type Config
- type ContentKind
- type ContentPart
- type Cursor
- type DiscoveryResult
- type EmbeddedRef
- type HealthBucket
- type HealthSnapshot
- type ImageRef
- type LinkRef
- type ListFilter
- type MCPToolValue
- type MCPTransportMode
- type ProbeResult
- type PromptArgView
- type PromptView
- type Provider
- func (p *Provider) Close(ctx context.Context) error
- func (p *Provider) Connect(ctx context.Context) error
- func (p *Provider) Discover(ctx context.Context) ([]tools.ToolDescriptor, error)
- func (p *Provider) SelectedMode() MCPTransportMode
- func (p *Provider) SourceID() tools.ToolSourceID
- func (p *Provider) SubscribeResource(ctx context.Context, uri string) error
- type ReconnectEntry
- type Registry
- func (r *Registry) GetServer(ctx context.Context, name string) (*ServerView, error)
- func (r *Registry) Health(ctx context.Context, name string, window time.Duration) (*HealthSnapshot, error)
- func (r *Registry) ListPrompts(ctx context.Context, name string) ([]PromptView, error)
- func (r *Registry) ListResources(ctx context.Context, name string) ([]ResourceView, error)
- func (r *Registry) ListServers(ctx context.Context, f ListFilter) ([]ServerView, *Cursor, error)
- func (r *Registry) Probe(ctx context.Context, name string) (*ProbeResult, error)
- func (r *Registry) RecordDiscovery(name string, descs []tools.ToolDescriptor) error
- func (r *Registry) RecordReconnect(name, reason string)
- func (r *Registry) RefreshDiscovery(ctx context.Context, name string) (*DiscoveryResult, error)
- func (r *Registry) Register(reg ServerRegistration) error
- func (r *Registry) SetRawHTMLTrust(ctx context.Context, name string, trusted bool) (prev bool, err error)
- type RegistryOption
- type ResourceUpdatedPayload
- type ResourceView
- type ServerRegistration
- type ServerState
- type ServerView
Constants ¶
const EventTypeMCPResourceUpdated events.EventType = "mcp.resource_updated"
EventTypeMCPResourceUpdated is the canonical event type emitted when the remote MCP server pushes a resource-update notification for a URI the driver previously subscribed to (Phase 28). The payload is SafePayload by construction — the URI is operator- trust-equivalent (it originates from an operator-configured MCP server) and the source ID is operator-supplied.
Variables ¶
var ( // ErrInvalidConfig — operator-side misconfiguration: missing URL // for HTTP-flavoured transports, missing Command for stdio, // unknown transport mode, etc. ErrInvalidConfig = errors.New("mcp: invalid config") // ErrTransportFailed — every candidate transport failed at // Connect time. The wrapped causes preserve the per-transport // failure messages. ErrTransportFailed = errors.New("mcp: transport failed") // ErrNotConnected — Discover / Invoke / SubscribeResource called // before Connect (or after Close). ErrNotConnected = errors.New("mcp: provider not connected") // ErrMCPToolError — the server returned a CallToolResult with // IsError == true. The wrapped message carries the rendered // text body. ErrMCPToolError = errors.New("mcp: server returned tool error") // ErrSchemaInvalid — the server-advertised InputSchema failed to // compile; the descriptor is rejected at Discover time so the // catalog never holds a Tool whose Validate is broken. ErrSchemaInvalid = errors.New("mcp: invalid tool input schema") // ErrIdentityMissing — the per-invocation ctx had no identity // triple. AGENTS.md §6 rule 9: identity is mandatory; the MCP // driver fails closed rather than dispatching to a remote server // with an empty `_meta` block. Mirrors the HTTP and A2A drivers. ErrIdentityMissing = errors.New("mcp: identity missing from ctx") )
Sentinel errors. Callers compare with errors.Is.
var ( // ErrServerNotFound — the named server is not registered. ErrServerNotFound = fmt.Errorf("mcp: server not found") // ErrRegistryIdentityMissing — the read ctx had no identity triple. // Identity is mandatory (AGENTS.md §6 rule 9); the read fails closed. ErrRegistryIdentityMissing = fmt.Errorf("mcp: identity missing from ctx") )
Sentinel errors. Callers compare with errors.Is.
Functions ¶
func Attach ¶ added in v1.3.0
func Attach(ctx context.Context, ms config.MCPServerConfig, deps AttachDeps) error
Attach wires one configured MCP server (config.MCPServerConfig) into the supplied catalog + registry. See the file doc for the full lifecycle. Every error is wrapped with the failing step so the boot path's `mcp[<name>]: ...` prefix pins the offending server.
func IsValidTransportMode ¶
IsValidTransportMode is the exported helper used by `internal/config` to validate the raw string from YAML.
func ProjectToolPolicies ¶ added in v1.3.0
func ProjectToolPolicies(ms config.MCPServerConfig) (tools.ToolPolicy, map[string]tools.ToolPolicy, error)
ProjectToolPolicies converts an MCPServerConfig's operator-facing policy YAML (Phase 26b) into the driver's runtime ToolPolicy fields: the per-server default and the per-tool override map (keyed by the MCP server-side tool name). The config package owns the single config→policy translation seam (config.ToolPolicyConfig.ToToolPolicy); this helper performs only the trivial primitive→tools.ToolPolicy copy. It lives next to the driver (Phase 110d, D-197 — promoted from cmd/harbor, where it was stranded because internal/config cannot import internal/tools). Any projection error (e.g. an unknown retry_on class) is returned so the boot path fails loud (CLAUDE.md §5).
A nil ms.Policy yields a zero-valued default policy, so the driver applies tools.DefaultPolicy() per-field at dispatch — preserving the no-policy behaviour exactly.
Types ¶
type AttachDeps ¶ added in v1.3.0
type AttachDeps struct {
// Catalog receives one ToolDescriptor per discovered tool.
Catalog tools.ToolCatalog
// Registry receives the live Provider registration so observability
// surfaces (the Console MCP Connections page) can project it.
Registry *Registry
// Bus carries the driver's mcp.* events. Mandatory — the driver's
// own constructor validates it (mcp.resource_updated emission).
Bus events.EventBus
// Logger receives the per-server attachment Info line. Optional.
Logger *slog.Logger
// DefaultIdentity is the FALLBACK identity stamped on server-pushed
// events that arrive without an inflight call (transport-side
// notifications — Phase 83m Item 1, D-156). Per-call subscriptions
// stamp the inflight caller's ctx-resident identity via the
// driver's pushIdentity helper; this default only covers
// transport-level events.
DefaultIdentity identity.Identity
// Closers is the caller's ordered closer chain. Attach appends the
// Provider's Close immediately after a successful Connect so a
// later Discover/Register failure still drains the live subprocess.
Closers *[]func(context.Context) error
}
AttachDeps bundles the collaborators Attach wires the server into. Catalog, Registry, Closers, and Bus are mandatory — a nil Bus fails loud at mcp.New (Config.validate rejects it; the driver publishes mcp.resource_updated). Only Logger is optional (a nil Logger silences the attachment log line — test stacks omit it).
type Config ¶
type Config struct {
// Name is the unique source ID prefix. Empty rejects with
// ErrInvalidConfig.
Name string
// TransportMode selects the wire transport. Empty defaults to
// TransportAuto.
TransportMode MCPTransportMode
// URL is the endpoint for SSE / streamable-HTTP transports.
// Required for those modes.
URL string
// Command is the argv-form subprocess command for the stdio
// transport. [0] is the binary; [1:] are args. Required for
// stdio. NEVER shell-form — the driver enforces this in
// transport_stdio.go.
Command []string
// Headers are operator-supplied HTTP headers added to every
// SSE / streamable-HTTP request (auth tokens, custom auth).
// "URL connections require explicit headers for auth (no
// implicit env passthrough)" — brief 03 §4.
Headers map[string]string
// KeepAlive is the ping interval for the MCP session; zero
// disables. The SDK's KeepAlive runs the underlying ping/pong.
KeepAlive time.Duration
// Logger is the per-provider slog logger. nil → a discard
// logger; runtime never panics on absent Logger.
Logger *slog.Logger
// Bus is the event bus used to publish `mcp.resource_updated`
// notifications. Required.
Bus events.EventBus
// DefaultPolicy is the ToolPolicy applied to descriptors built
// from this provider. Zero-valued → tools.DefaultPolicy().
DefaultPolicy tools.ToolPolicy
// ToolPolicies are per-tool ToolPolicy overrides keyed by the
// MCP server-side tool name (NOT the `<source>_<tool>` Harbor
// name). When a discovered tool's name is present here, its
// descriptor uses the override instead of DefaultPolicy; a tool
// absent from the map falls back to DefaultPolicy (Phase 26b).
// Per-tool overrides apply to TOOLS only — MCP resources and
// prompts always run under DefaultPolicy (the per-server default).
//
// Concurrent reuse (D-025): the map is read-only after New — it is
// never mutated per-run. buildToolDescriptor only reads it, and
// the resolved ToolPolicy is copied by value into each descriptor
// at Discover time, so concurrent invocations of different tools
// never share or race this map.
ToolPolicies map[string]tools.ToolPolicy
// DefaultIdentity is the fallback identity stamped on
// transport-side events (notifications that arrive without an
// inflight call). Required so the bus's ValidateEvent does not
// reject the event when the SDK-supplied ctx carries no triple.
//
// Phase 83m (Item 1, D-156): the role narrows. For events the
// SDK delivers WITH a populated ctx (per-call notifications
// originating from an inflight tool / resource subscription),
// the driver prefers `identity.From(ctx)` over this cached
// default — `pushIdentity(ctx, cfg)` is the single helper that
// implements the preference. The DefaultIdentity remains the
// fallback for genuine transport-level events (a server-pushed
// `notifications/resources/updated` arriving outside any
// inflight call) where the ctx has no triple to read.
DefaultIdentity identity.Identity
}
Config is the operator-supplied configuration for one MCP attachment. Operator-facing fields map 1:1 to the `config.MCPServerConfig` yaml shape; the runtime entry point (cmd/harbor wiring, future phase) is responsible for the projection.
type ContentKind ¶
type ContentKind string
ContentKind discriminates a ContentPart.
const ( ContentKindImage ContentKind = "image" ContentKindAudio ContentKind = "audio" ContentKindLink ContentKind = "link" ContentKindEmbedded ContentKind = "embedded" )
The ContentKind values, one per MCP content-part shape.
type ContentPart ¶
type ContentPart struct {
Kind ContentKind
Image *ImageRef
Audio *AudioRef
Link *LinkRef
Embedded *EmbeddedRef
}
ContentPart is the discriminated union of non-text content shapes. Exactly one of Image / Audio / Link / Embedded is set; Kind names which.
type Cursor ¶
type Cursor struct {
// NextPageToken is the cursor for the next page, or empty when the
// page is the last.
NextPageToken string
}
Cursor is the opaque pagination cursor a paged read returns.
type DiscoveryResult ¶
DiscoveryResult is the outcome of a RefreshDiscovery call.
type EmbeddedRef ¶
EmbeddedRef is the lowered form of an MCP EmbeddedResource (a resource embedded directly in the tool call result).
type HealthBucket ¶
HealthBucket is one handshake-latency sparkline bucket.
type HealthSnapshot ¶
type HealthSnapshot struct {
HandshakeLatencyBuckets []HealthBucket
ReconnectHistory []ReconnectEntry
TransportErrorRate float64
}
HealthSnapshot is the Health read result.
type LinkRef ¶
LinkRef is the lowered form of an MCP ResourceLink (a pointer to a resource the server hosts; the client may follow it with ReadResource if desired).
type ListFilter ¶
type ListFilter struct {
// State filters to servers in any of the given states. Empty = all.
State []ServerState
// Transport filters to servers on any of the given transports.
Transport []string
// HasOAuth, when set, filters on OAuth-binding presence.
HasOAuth *bool
// HasRecentError, when set, filters on recent-error presence.
HasRecentError *bool
// NamePrefix filters to servers whose name has the prefix.
NamePrefix string
// PageToken is the opaque cursor from a prior page.
PageToken string
// PageSize is the requested max row count (clamped by the Registry).
PageSize int
}
ListFilter is the filter shape ListServers applies.
type MCPToolValue ¶
type MCPToolValue struct {
// Text concatenates every TextContent block in encounter order.
Text string
// Parts is the ordered, typed slice of every non-text content
// block. Empty when the response is pure text.
Parts []ContentPart
// StructuredContent is the MCP `structuredContent` field on
// servers that support typed JSON output (mcpsdk.ToolHandlerFor).
// nil when absent.
StructuredContent any
}
MCPToolValue is the typed shape returned from `Invoke` when the remote MCP server returns a CallToolResult. Heterogeneous parts preserve the wire ordering so downstream consumers (LLM context assembly, audit) can reconstruct the server's response.
func (MCPToolValue) MarshalJSON ¶ added in v1.2.0
func (v MCPToolValue) MarshalJSON() ([]byte, error)
MarshalJSON renders the value LLM-edge-friendly. The text-only degenerate case (Parts + StructuredContent both empty) emits just the raw Text — most MCP tools return their result as a TextContent block carrying JSON-as-string, and the default struct marshal produces a `{"Text": "<escaped JSON>"}` wrapper that doubles the encoding. When Text is itself well-formed JSON, MarshalJSON emits the JSON value directly so the LLM reads a clean structure; otherwise the text rides as a JSON string. Audit / observability consumers that need the typed shape can re-derive it from the underlying CallToolResult on the bus.
When StructuredContent is set, it wins (it's the MCP-server-typed projection). When Parts are non-empty, the wrapper carries the non-text shape verbatim — there is no clean unwrap for mixed- content responses, so the default struct render applies.
type MCPTransportMode ¶
type MCPTransportMode string
MCPTransportMode selects the wire transport for one MCP attachment. Mirrors brief 03 §4 ("`MCPTransportMode = Auto | SSE | StreamableHTTP`"). Stdio is the implicit fourth mode: selected when `Auto` sees a `Command` but no `URL`.
const ( // TransportAuto inspects Config and picks: streamable-HTTP first // if URL is set; on connect failure fall back to SSE; if Command // is set with no URL, stdio. TransportAuto MCPTransportMode = "auto" // TransportSSE selects the SDK's SSEClientTransport. URL must // be set. TransportSSE MCPTransportMode = "sse" // TransportStreamableHTTP selects the SDK's // StreamableClientTransport. URL must be set. TransportStreamableHTTP MCPTransportMode = "streamable_http" // TransportStdio selects the SDK's CommandTransport. Command // (argv form) must be set. TransportStdio MCPTransportMode = "stdio" )
type ProbeResult ¶
ProbeResult is the outcome of a Probe call.
type PromptArgView ¶
PromptArgView is one declared prompt argument.
type PromptView ¶
type PromptView struct {
Name string
Description string
Arguments []PromptArgView
}
PromptView is one advertised prompt.
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider implements tools.ToolProvider against a remote MCP server. Safe for N concurrent goroutines after Connect (D-025); per-call state lives on the call's ctx, never on the Provider.
Concurrent reuse contract:
- `session` is set once by Connect under mu; subsequent reads are guarded by mu.RLock so Invoke / Discover / Close races are safe.
- `closed` flips to true on Close; subsequent Invoke / Discover return ErrNotConnected.
- The resource-update goroutine reads `session` once at Connect time and exits when the session closes.
func New ¶
New constructs a Provider. The Provider is NOT connected; the caller MUST call Connect before Discover / Invoke / SubscribeResource.
func (*Provider) Close ¶
Close shuts the session down idempotently and joins any in-flight SDK goroutines. Safe to call multiple times.
func (*Provider) Connect ¶
Connect establishes the MCP session. Calling Connect twice without an interleaving Close returns the existing session (Connect is idempotent on the second call only when the first succeeded).
Auto-mode fallback: when TransportMode is TransportAuto and the URL is set, the Provider tries streamable-HTTP first. On a non-cancellation failure of `client.Connect` (which covers both transport-Connect and the MCP initialize handshake), it retries with SSE.
func (*Provider) Discover ¶
Discover returns one ToolDescriptor per remote tool, plus one per resource (rendered as a `__resource.<uri>` tool) and one per prompt (`__prompt.<name>`). All descriptors carry Transport = TransportMCP and Source = p.source.
func (*Provider) SelectedMode ¶
func (p *Provider) SelectedMode() MCPTransportMode
SelectedMode reports the transport mode that succeeded at Connect time. Empty before Connect.
func (*Provider) SourceID ¶
func (p *Provider) SourceID() tools.ToolSourceID
SourceID returns the source ID under which this provider's descriptors are stamped. Implements tools.ToolProvider.
func (*Provider) SubscribeResource ¶
SubscribeResource registers a server-side resource subscription. Updates received via the SDK's ResourceUpdatedHandler are published as `mcp.resource_updated` on the configured event bus (see Provider.onResourceUpdated).
type ReconnectEntry ¶
ReconnectEntry is one reconnect-history entry.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is the process-local MCP-server read API. It is a compiled artifact (D-025) — built once at construction; the provider set is write-once after Register; per-server stats are guarded by mu.
func NewRegistry ¶
func NewRegistry(opts ...RegistryOption) *Registry
NewRegistry builds an empty Registry. Servers are added via Register.
func (*Registry) Health ¶
func (r *Registry) Health(ctx context.Context, name string, window time.Duration) (*HealthSnapshot, error)
Health returns the per-server handshake-latency sparkline + reconnect history + transport-error rate. The window argument bounds the reconnect-history slice. Identity is mandatory.
func (*Registry) ListPrompts ¶
ListPrompts returns the advertised prompts for a server. Identity is mandatory.
func (*Registry) ListResources ¶
ListResources returns the advertised resources for a server. It runs a Discover and projects the synthetic resource descriptors. Identity is mandatory.
func (*Registry) ListServers ¶
func (r *Registry) ListServers(ctx context.Context, f ListFilter) ([]ServerView, *Cursor, error)
ListServers returns the filtered, paginated server list. The view shapes are projection-only; no per-call state lives on the Registry (D-025). Identity is mandatory.
func (*Registry) Probe ¶
Probe runs a transport round-trip (a Discover acting as a tools/list ping) and returns the latency. Identity is mandatory.
func (*Registry) RecordDiscovery ¶
func (r *Registry) RecordDiscovery(name string, descs []tools.ToolDescriptor) error
RecordDiscovery seeds the per-server stats from an already-fetched descriptor slice without re-calling provider.Discover. The boot-time dev attach path uses this so the Console MCP-page wire surface (`mcp.servers.list`) reports the actual tool count + a real `last_discovery_at`, not zero values.
Pre-RecordDiscovery the boot-time path called Register() with initial-zero stats; the only API that updated stats was RefreshDiscovery, which re-runs the network call. Operators saw `tool_count: 0` and `last_discovery_at: 0001-01-01T00:00:00Z` on every just-booted Runtime because the boot-time discovery never reached the registry's stats — its result went straight to the tool catalog. Round-4 walkthrough fix.
RecordDiscovery is a no-network counterpart to RefreshDiscovery: caller already has the descriptors (from a previous provider.Discover at boot), so the method just classifies them + writes the stats. State is set to Online (the descriptors arrived successfully) and recentLatencyMs is set to 0 (the boot-time latency is not threaded through; a follow-up RefreshDiscovery from the Console will populate it).
Identity is NOT required — this is a server-side seeding gesture from the boot path, not a Protocol-edge read.
func (*Registry) RecordReconnect ¶
RecordReconnect appends a reconnect-history entry. The runtime wires this to the transport-reconnect path; tests call it directly.
func (*Registry) RefreshDiscovery ¶
RefreshDiscovery re-runs the named server's discovery and updates the per-server counts + state. Identity is mandatory.
func (*Registry) Register ¶
func (r *Registry) Register(reg ServerRegistration) error
Register adds a server to the Registry. Re-registering the same name replaces the prior entry (the dev hot-reload path re-registers).
func (*Registry) SetRawHTMLTrust ¶
func (r *Registry) SetRawHTMLTrust(ctx context.Context, name string, trusted bool) (prev bool, err error)
SetRawHTMLTrust persists the per-server raw-HTML trust flag in the runtime-side mirror (the legitimate D-061 carve-out for a preference with audit consequences). It returns the prior value so a caller can detect a no-op toggle. Identity is mandatory.
type RegistryOption ¶
type RegistryOption func(*Registry)
RegistryOption configures a Registry at construction.
func WithRegistryClock ¶
func WithRegistryClock(now func() time.Time) RegistryOption
WithRegistryClock overrides the Registry's wall clock — tests inject a deterministic clock so latency / timestamps are stable.
type ResourceUpdatedPayload ¶
type ResourceUpdatedPayload struct {
events.SafeSealed
Identity identity.Quadruple
Source tools.ToolSourceID
URI string
OccurredAt time.Time
}
ResourceUpdatedPayload is the typed payload for EventTypeMCPResourceUpdated. SafePayload: no caller-controlled bytes survive on the payload.
- Identity scopes the event to the (tenant, user, session) triple under which the resource subscription was registered.
- Source is the originating MCP attachment's source ID, so subscribers can route by provider.
- URI is the resource URI the server reported as updated; this may be a sub-resource of the URI the client actually subscribed to.
- OccurredAt is the wall-clock time the driver received the notification.
type ResourceView ¶
ResourceView is one advertised resource.
type ServerRegistration ¶
type ServerRegistration struct {
// Provider is the live MCP provider. Required.
Provider serverProvider
// Transport is the wire transport string ("stdio" / "http+sse" /
// "streamable-http" / "websocket"). Required.
Transport string
// URLOrCommand is the transport-prefixed endpoint or argv command.
URLOrCommand string
// Policy is the server's ToolPolicy. Zero-valued → DefaultPolicy.
Policy tools.ToolPolicy
// DisplayModes lists the advertised MCP-Apps DisplayMode values.
DisplayModes []string
// ContentShapes lists the canonical content shapes the tools return.
ContentShapes []string
// OAuthBindingCount is the configured OAuth binding count.
OAuthBindingCount int
// InitialState is the server's starting state. Zero-valued →
// ServerStateOffline.
InitialState ServerState
}
ServerRegistration is the operator-supplied static descriptor for one MCP server attachment the Registry tracks.
type ServerState ¶
type ServerState string
ServerState mirrors the canonical state chip the Console renders. The V1 set is closed.
const ( // ServerStateOnline — transport connected, last discovery / probe // succeeded. ServerStateOnline ServerState = "online" // ServerStateReconnecting — transport dropped, re-establishing. ServerStateReconnecting ServerState = "reconnecting" // ServerStateOffline — transport down (never connected / closed). ServerStateOffline ServerState = "offline" // ServerStateAuthPending — server needs an incomplete OAuth binding. ServerStateAuthPending ServerState = "auth_pending" // ServerStateError — last discovery / probe failed. ServerStateError ServerState = "error" )
The canonical MCP server states.
type ServerView ¶
type ServerView struct {
// Name is the unique server / source id.
Name string
// Transport is the wire transport string.
Transport string
// URLOrCommand is the transport-prefixed endpoint or argv command.
URLOrCommand string
// State is the canonical state chip.
State ServerState
// LastDiscoveryAt is the last successful discovery instant (zero
// when discovery has never run).
LastDiscoveryAt time.Time
// ToolCount / ResourceCount / PromptCount are the advertised counts.
ToolCount int
ResourceCount int
PromptCount int
// RecentLatencyMs is the most recent observed handshake / probe
// latency.
RecentLatencyMs int64
// ErrorRatePerMin is the transport-error rate over the window.
ErrorRatePerMin float64
// OAuthBindingCount is the number of OAuth bindings configured.
OAuthBindingCount int
// RawHTMLTrusted reports the per-server raw-HTML trust flag.
RawHTMLTrusted bool
// DisplayModes lists the advertised MCP-Apps DisplayMode values.
DisplayModes []string
// ContentShapes lists the canonical content shapes the server's
// tools return.
ContentShapes []string
// Policy is the read-only ToolPolicy projection.
Policy tools.ToolPolicy
}
ServerView is the per-server projection the Registry returns. It is a flat shape — no MCP-SDK type crosses the package boundary.