config: the MCP block itself joins mcp.go (V-410)
Second half of the move. MCPConfig, DefaultMCPHostInterval and the normalise arm now sit next to the server struct they govern; applyDefaults calls normaliseMCP instead of inlining it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -286,42 +286,6 @@ type Config struct {
|
||||
NetScan *NetScanConfig `json:"netscan,omitempty"`
|
||||
}
|
||||
|
||||
// MCPConfig — the MCP client block. Servers are dark until one has
|
||||
// `"enabled": true`, and a discovered tool is only ever PROPOSED: Kami enables
|
||||
// it on /tools, on the authed surface, exactly as he would a shell tool. The
|
||||
// voice path can never grant a capability to itself.
|
||||
type MCPConfig struct {
|
||||
// Servers — the configured servers. Each needs exactly one of command
|
||||
// (a subprocess on this box) or url (a streamable-HTTP endpoint).
|
||||
Servers []MCPServerConfig `json:"servers,omitempty"`
|
||||
|
||||
// Timeout — per-call budget for every server that does not set its own.
|
||||
// 0 ⇒ mcp.DefaultTimeout (15s). A tool slower than this is not usable in a
|
||||
// spoken turn.
|
||||
Timeout Duration `json:"timeout,omitempty"`
|
||||
|
||||
// AllowHosts / DenyHosts — the host lists for the shared webfetch door that
|
||||
// url servers go through. Deny wins. Private addresses are refused
|
||||
// unconditionally unless the individual server sets allow_private.
|
||||
AllowHosts []string `json:"allow_hosts,omitempty"`
|
||||
DenyHosts []string `json:"deny_hosts,omitempty"`
|
||||
|
||||
// MaxBytes — cap on one JSON-RPC response. 0 ⇒ webfetch.DefaultMaxBytes.
|
||||
MaxBytes int64 `json:"max_bytes,omitempty"`
|
||||
|
||||
// HostInterval — minimum spacing between two requests to one MCP server.
|
||||
// 0 ⇒ DefaultMCPHostInterval (50ms), NOT webfetch's own one-second default.
|
||||
// That default was sized for a feed poll loop, and this path is in a spoken
|
||||
// turn: one dial is three requests (initialize, initialized, tools/list),
|
||||
// so a second of spacing is two seconds of pure sleeping per dial and up to
|
||||
// another second before every tools/call leaves the box.
|
||||
HostInterval Duration `json:"host_interval,omitempty"`
|
||||
}
|
||||
|
||||
// DefaultMCPHostInterval — see MCPConfig.HostInterval. Enough to stop a
|
||||
// runaway loop hammering a server, small enough not to be heard.
|
||||
const DefaultMCPHostInterval = 50 * time.Millisecond
|
||||
|
||||
// SmartHomeConfig — the Home Assistant block (Vikunja #256). Dark until
|
||||
// `"enabled": true`, and even then a discovered device is only ever PROPOSED
|
||||
// into the act allowlist: Kami enables it on /tools, behind step-up, exactly as
|
||||
@@ -1393,18 +1357,7 @@ func (c *Config) applyDefaults() {
|
||||
c.Feeds = nil
|
||||
}
|
||||
|
||||
// Same rule for MCP: a block with no server at all is the same as no block.
|
||||
// A block whose servers are all disabled is NOT normalised away, because
|
||||
// validate has to see their shape — a dark block with a typo in it should
|
||||
// fail at startup, which is the whole reason it can be written before it is
|
||||
// switched on. wireMCP builds nothing when nothing is enabled, so "off"
|
||||
// still holds.
|
||||
if c.MCP != nil && len(c.MCP.Servers) == 0 {
|
||||
c.MCP = nil
|
||||
}
|
||||
if c.MCP != nil && c.MCP.HostInterval <= 0 {
|
||||
c.MCP.HostInterval = Duration(DefaultMCPHostInterval)
|
||||
}
|
||||
c.normaliseMCP()
|
||||
|
||||
// Same rule for the house: a block that is not enabled is the same as no
|
||||
// block at all, so "off" stays in one place.
|
||||
|
||||
@@ -6,6 +6,57 @@ import (
|
||||
"github.com/kami/maven/internal/mcp"
|
||||
)
|
||||
|
||||
// MCPConfig — the MCP client block. Servers are dark until one has
|
||||
// `"enabled": true`, and a discovered tool is only ever PROPOSED: Kami enables
|
||||
// it on /tools, on the authed surface, exactly as he would a shell tool. The
|
||||
// voice path can never grant a capability to itself.
|
||||
type MCPConfig struct {
|
||||
// Servers — the configured servers. Each needs exactly one of command
|
||||
// (a subprocess on this box) or url (a streamable-HTTP endpoint).
|
||||
Servers []MCPServerConfig `json:"servers,omitempty"`
|
||||
|
||||
// Timeout — per-call budget for every server that does not set its own.
|
||||
// 0 ⇒ mcp.DefaultTimeout (15s). A tool slower than this is not usable in a
|
||||
// spoken turn.
|
||||
Timeout Duration `json:"timeout,omitempty"`
|
||||
|
||||
// AllowHosts / DenyHosts — the host lists for the shared webfetch door that
|
||||
// url servers go through. Deny wins. Private addresses are refused
|
||||
// unconditionally unless the individual server sets allow_private.
|
||||
AllowHosts []string `json:"allow_hosts,omitempty"`
|
||||
DenyHosts []string `json:"deny_hosts,omitempty"`
|
||||
|
||||
// MaxBytes — cap on one JSON-RPC response. 0 ⇒ webfetch.DefaultMaxBytes.
|
||||
MaxBytes int64 `json:"max_bytes,omitempty"`
|
||||
|
||||
// HostInterval — minimum spacing between two requests to one MCP server.
|
||||
// 0 ⇒ DefaultMCPHostInterval (50ms), NOT webfetch's own one-second default.
|
||||
// That default was sized for a feed poll loop, and this path is in a spoken
|
||||
// turn: one dial is three requests (initialize, initialized, tools/list),
|
||||
// so a second of spacing is two seconds of pure sleeping per dial and up to
|
||||
// another second before every tools/call leaves the box.
|
||||
HostInterval Duration `json:"host_interval,omitempty"`
|
||||
}
|
||||
|
||||
// DefaultMCPHostInterval — see MCPConfig.HostInterval. Enough to stop a
|
||||
// runaway loop hammering a server, small enough not to be heard.
|
||||
const DefaultMCPHostInterval = 50 * time.Millisecond
|
||||
|
||||
// normaliseMCP applies the block's defaults. A block with no server at all is
|
||||
// the same as no block. A block whose servers are all disabled is NOT
|
||||
// normalised away, because validate has to see their shape — a dark block with
|
||||
// a typo in it should fail at startup, which is the whole reason it can be
|
||||
// written before it is switched on. wireMCP builds nothing when nothing is
|
||||
// enabled, so "off" still holds.
|
||||
func (c *Config) normaliseMCP() {
|
||||
if c.MCP != nil && len(c.MCP.Servers) == 0 {
|
||||
c.MCP = nil
|
||||
}
|
||||
if c.MCP != nil && c.MCP.HostInterval <= 0 {
|
||||
c.MCP.HostInterval = Duration(DefaultMCPHostInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// MCPServerConfig — one MCP server.
|
||||
type MCPServerConfig struct {
|
||||
// Name — the local handle. It prefixes every tool this server contributes
|
||||
|
||||
Reference in New Issue
Block a user