Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ full command and press `⏎`.
| `/memory` | Facts by target, pending-episode promote, consolidate |
| `/skills` | Skill provenance badges & promote |
| `/tools` | Tool registry with enabled state & MCP servers |
| `/mcp` | MCP servers — `/mcp [name]` jumps to one in the tools drawer |
| `/mcp` | MCP servers with enabled/disabled state — `/mcp [name]` jumps to one in the tools drawer |
| `/config` | Sanitized config, lifetime usage, connections (kick) |
| `/model [name]` | Switch model (opens a picker with no argument) |
| `/thinking [disabled\|low\|medium\|high]` | Set reasoning depth (`on` → `medium`, `off` → `disabled`, `inherit` restores the odek serve default; bare `/thinking` opens a picker) |
Expand Down
1 change: 1 addition & 0 deletions internal/client/manage.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type MCPServer struct {
Args []string `json:"args,omitempty"`
Project bool `json:"project,omitempty"`
AutoApprove bool `json:"auto_approve,omitempty"`
Enabled bool `json:"enabled"`
TimeoutSeconds int `json:"timeout_seconds,omitempty"`
MaxResponseBytes int64 `json:"max_response_bytes,omitempty"`
MaxResultChars int `json:"max_result_chars,omitempty"`
Expand Down
44 changes: 44 additions & 0 deletions internal/tui/mcp_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,50 @@ func TestMCPUnknownNotClobbered(t *testing.T) {
}
}

// TestMCPEnabledStateVisible verifies MCP rows and the detail view surface
// the enabled/disabled state odek sends on /api/mcp.
func TestMCPEnabledStateVisible(t *testing.T) {
m := newTestModel()
m.panel = panelTools
m.handleMgmtMsg(mgmtMsg{tab: panelTools, mcpN: 2, tls: []client.Tool{{Name: "shell", Enabled: true}},
mcp: []client.MCPServer{
{Name: "fs", Command: "bun", Enabled: true},
{Name: "vault", Command: "node", Enabled: false},
}})
if len(m.toolRows) != 3 {
t.Fatalf("toolRows = %d, want 3", len(m.toolRows))
}
var fsRow, vaultRow *toolRow
for i := range m.toolRows {
switch r := &m.toolRows[i]; r.id {
case "fs":
fsRow = r
case "vault":
vaultRow = r
}
}
if fsRow == nil || vaultRow == nil {
t.Fatalf("missing mcp rows: %+v", m.toolRows)
}
if !strings.Contains(fsRow.dim, "enabled") || strings.Contains(fsRow.dim, "disabled") {
t.Errorf("fs row dim = %q, want an \"enabled\" marker", fsRow.dim)
}
if !strings.Contains(vaultRow.dim, "disabled") {
t.Errorf("vault row dim = %q, want \"disabled\" marker", vaultRow.dim)
}
// Detail view of the disabled server states the fact explicitly.
for i := range m.toolRows {
if m.toolRows[i].id == "vault" {
m.panelSel = i
}
}
m.panelDetail = true
out := plain(m.View())
if !strings.Contains(out, "disabled") {
t.Errorf("mcp detail view missing \"disabled\":\n%s", out)
}
}

// TestMCPZeroServers verifies the zero-server empty state: the Tools tab
// still opens (it has native tools) with a "no MCP servers configured" note.
func TestMCPZeroServers(t *testing.T) {
Expand Down
10 changes: 10 additions & 0 deletions internal/tui/mgmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@ func buildToolRows(tools []client.Tool, servers []client.MCPServer) []toolRow {
}
for _, s := range servers {
detail := s.Command
if s.Enabled {
detail += " · enabled"
} else {
detail += " · disabled"
}
if s.Project {
detail += " · project"
}
Expand Down Expand Up @@ -935,6 +940,11 @@ func (m *Model) mgmtDetailLines(w int) []string {
}
out = append(out, th.acDetail.Render(cmd))
var meta []string
if srv.Enabled {
meta = append(meta, "enabled")
} else {
meta = append(meta, "disabled")
}
if srv.Project {
meta = append(meta, "project-scoped")
}
Expand Down
Loading