Skip to content

Commit 546a239

Browse files
authored
feat(httpapi): expose default MCP instructions via /api/v1/status (#652)
Exposes `default_instructions` (the resolved built-in default from `resolveInstructions("")`) on `GET /api/v1/status`, so the Web UI can render it as the placeholder for the `instructions` setting without hardcoding the text (drift-safe). Backend half of MCP-2175. All required checks green incl. qa-gate (QATester MCP-2180). Merged under explicit owner authorization (author == maintainer gh identity, non-author approval not self-satisfiable).
1 parent 2505c19 commit 546a239

6 files changed

Lines changed: 64 additions & 0 deletions

File tree

internal/httpapi/contracts_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ func (m *MockServerController) GetConfig() (*config.Config, error) {
289289
}, nil
290290
}
291291

292+
func (m *MockServerController) DefaultInstructions() string {
293+
return "test built-in default: use retrieve_tools to discover tools"
294+
}
295+
292296
// Readiness method
293297
func (m *MockServerController) IsReady() bool { return true }
294298

internal/httpapi/routing_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,33 @@ func TestHandleGetStatus_IncludesRoutingMode(t *testing.T) {
180180
assert.Equal(t, config.RoutingModeRetrieveTools, resp.Data["routing_mode"])
181181
})
182182
}
183+
184+
// TestHandleGetStatus_IncludesDefaultInstructions verifies the status response
185+
// exposes the built-in default MCP instructions so the Web UI can render them as
186+
// the instructions textarea placeholder without hardcoding the text (MCP-2176).
187+
func TestHandleGetStatus_IncludesDefaultInstructions(t *testing.T) {
188+
logger := zap.NewNop().Sugar()
189+
mockCtrl := &mockRoutingController{apiKey: "test-key", routingMode: ""}
190+
srv := NewServer(mockCtrl, logger, nil)
191+
192+
req := httptest.NewRequest(http.MethodGet, "/api/v1/status", nil)
193+
req.Header.Set("X-API-Key", "test-key")
194+
w := httptest.NewRecorder()
195+
196+
srv.ServeHTTP(w, req)
197+
198+
assert.Equal(t, http.StatusOK, w.Code)
199+
200+
var resp struct {
201+
Success bool `json:"success"`
202+
Data map[string]interface{} `json:"data"`
203+
}
204+
err := json.NewDecoder(w.Body).Decode(&resp)
205+
require.NoError(t, err)
206+
require.True(t, resp.Success)
207+
208+
defaultInstructions, ok := resp.Data["default_instructions"].(string)
209+
require.True(t, ok, "default_instructions must be present and a string")
210+
assert.NotEmpty(t, defaultInstructions)
211+
assert.Contains(t, defaultInstructions, "retrieve_tools")
212+
}

internal/httpapi/security_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,6 @@ func (m *baseController) GetOnboardingState() (*storage.OnboardingState, error)
361361
}
362362
func (m *baseController) SaveOnboardingState(_ *storage.OnboardingState) error { return nil }
363363
func (m *baseController) GetActivationFirstMCPClient() (bool, []string) { return false, nil }
364+
func (m *baseController) DefaultInstructions() string {
365+
return "test built-in default: use retrieve_tools to discover tools"
366+
}

internal/httpapi/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ type ServerController interface {
109109
ValidateConfig(cfg *config.Config) ([]config.ValidationError, error)
110110
ApplyConfig(cfg *config.Config, cfgPath string) (*internalRuntime.ConfigApplyResult, error)
111111
GetConfig() (*config.Config, error)
112+
// DefaultInstructions returns the built-in default MCP instructions text
113+
// (independent of any user-configured custom value), so /api/v1/status can
114+
// surface it to the Web UI as the instructions placeholder (MCP-2176).
115+
DefaultInstructions() string
112116

113117
// Token statistics
114118
GetTokenSavings() (*contracts.ServerTokenMetrics, error)
@@ -912,6 +916,11 @@ func (s *Server) handleGetStatus(w http.ResponseWriter, _ *http.Request) {
912916
"status": s.controller.GetStatus(),
913917
"routing_mode": routingMode,
914918
"timestamp": time.Now().Unix(),
919+
// MCP-2176: built-in default MCP instructions. The Web UI renders this
920+
// as the instructions textarea placeholder so the displayed default
921+
// never drifts from the backend's resolveInstructions("") value. Always
922+
// the built-in default, never the user's current custom value.
923+
"default_instructions": s.controller.DefaultInstructions(),
915924
}
916925

917926
// Spec 044 (FR-018): expose process-level env_kind + env_markers so the

internal/server/mcp_instructions_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ func TestResolveInstructions_Custom(t *testing.T) {
1717
assert.Equal(t, custom, result)
1818
}
1919

20+
// TestServer_DefaultInstructions verifies the controller exposes the built-in
21+
// default (not a user's custom value) so /api/v1/status can surface it to the
22+
// Web UI placeholder without drift (MCP-2176).
23+
func TestServer_DefaultInstructions(t *testing.T) {
24+
s := &Server{}
25+
assert.Equal(t, defaultInstructions, s.DefaultInstructions())
26+
assert.Contains(t, s.DefaultInstructions(), "retrieve_tools")
27+
}
28+
2029
func TestDefaultInstructions_ContainsKeyTerms(t *testing.T) {
2130
assert.Contains(t, defaultInstructions, "retrieve_tools")
2231
assert.Contains(t, defaultInstructions, "search_servers")

internal/server/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2205,6 +2205,15 @@ func (s *Server) GetConfig() (*config.Config, error) {
22052205
return s.runtime.GetConfig()
22062206
}
22072207

2208+
// DefaultInstructions returns the built-in default MCP instructions text,
2209+
// independent of any user-configured custom value. It backs the
2210+
// /api/v1/status `default_instructions` field so the Web UI can render the
2211+
// built-in default as the instructions placeholder without hardcoding the
2212+
// text (MCP-2176). This mirrors resolveInstructions("").
2213+
func (s *Server) DefaultInstructions() string {
2214+
return defaultInstructions
2215+
}
2216+
22082217
// ValidateConfig validates a configuration
22092218
func (s *Server) ValidateConfig(cfg *config.Config) ([]config.ValidationError, error) {
22102219
return s.runtime.ValidateConfig(cfg)

0 commit comments

Comments
 (0)