diff --git a/internal/daemon/run.go b/internal/daemon/run.go index dac28f8..b2a3ea6 100644 --- a/internal/daemon/run.go +++ b/internal/daemon/run.go @@ -17,6 +17,8 @@ import ( "github.com/doITmagic/rag-code-mcp/internal/healthcheck" "github.com/doITmagic/rag-code-mcp/internal/logger" "github.com/doITmagic/rag-code-mcp/internal/service/engine" + "github.com/doITmagic/rag-code-mcp/internal/service/prompts" + "github.com/doITmagic/rag-code-mcp/internal/service/resources" "github.com/doITmagic/rag-code-mcp/internal/service/search" "github.com/doITmagic/rag-code-mcp/internal/service/tools" "github.com/doITmagic/rag-code-mcp/internal/transport" @@ -173,6 +175,10 @@ func Run(rcfg RunConfig) error { logger.Instance.Info("Update tools registered (auto_update=false)") } + // Register Extra Features (Resources & Prompts MVP) + resources.Register(mcpServer, eng) + prompts.Register(mcpServer, eng) + logger.Instance.Info("MCP RagCode Daemon initialized (version=%s)", rcfg.Version) if cfg.AutoUpdate { diff --git a/internal/service/prompts/prompts.go b/internal/service/prompts/prompts.go new file mode 100644 index 0000000..3035e87 --- /dev/null +++ b/internal/service/prompts/prompts.go @@ -0,0 +1,41 @@ +package prompts + +import ( + "context" + "fmt" + + "github.com/doITmagic/rag-code-mcp/internal/service/engine" + "github.com/modelcontextprotocol/go-sdk/mcp" +) + +// Register registers all MCP prompts provided by this package on the given mcp.Server. +func Register(mcpServer *mcp.Server, eng *engine.Engine) { + mcpServer.AddPrompt(&mcp.Prompt{ + Name: "System Diagnostics", + Description: "Analyze the current indexing status and troubleshoot common issues based on the workspace resources.", + Title: "Analyze RagCode Indexing System", + }, func(ctx context.Context, request *mcp.GetPromptRequest) (*mcp.GetPromptResult, error) { + // Detect workspace to contextualize the prompt + wctx, err := eng.DetectContext(ctx, "") + if err != nil { + return nil, fmt.Errorf("failed to detect workspace: %w", err) + } + + promptText := fmt.Sprintf(`Please analyze the current indexing status of the RagCode MCP server for the workspace located at: %s + +You can inspect the indexing status by reading the resource directly via URI: "ragcode://status/indexing" or using your available tools. +Then, inform me if there are any issues such as stuck processes or parsing errors.`, wctx.Root) + + return &mcp.GetPromptResult{ + Description: "Prompt to diagnose indexing and execution issues automatically.", + Messages: []*mcp.PromptMessage{ + { + Role: mcp.Role("user"), + Content: &mcp.TextContent{ + Text: promptText, + }, + }, + }, + }, nil + }) +} diff --git a/internal/service/resources/resources.go b/internal/service/resources/resources.go new file mode 100644 index 0000000..862cfdd --- /dev/null +++ b/internal/service/resources/resources.go @@ -0,0 +1,46 @@ +package resources + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/doITmagic/rag-code-mcp/internal/service/engine" + "github.com/modelcontextprotocol/go-sdk/mcp" +) + +// Register registers all MCP resources provided by this package on the given mcp.Server. +func Register(mcpServer *mcp.Server, eng *engine.Engine) { + mcpServer.AddResource(&mcp.Resource{ + URI: "ragcode://status/indexing", + Name: "Indexing Status", + Description: "Returns the current indexing status and progress for the workspace.", + MIMEType: "application/json", + }, func(ctx context.Context, request *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) { + // Attempt to resolve context + wctx, err := eng.DetectContext(ctx, "") + if err != nil { + return nil, fmt.Errorf("failed to detect workspace: %w", err) + } + + status := eng.GetIndexStatus(wctx.Root) + if status == nil { + return nil, fmt.Errorf("index status not found for workspace %s", wctx.Root) + } + + blob, err := json.MarshalIndent(status, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal index status: %w", err) + } + + return &mcp.ReadResourceResult{ + Contents: []*mcp.ResourceContents{ + { + URI: request.Params.URI, + Text: string(blob), + MIMEType: "application/json", + }, + }, + }, nil + }) +} diff --git a/internal/service/tools/call_hierarchy.go b/internal/service/tools/call_hierarchy.go index 14ee722..24f82a9 100644 --- a/internal/service/tools/call_hierarchy.go +++ b/internal/service/tools/call_hierarchy.go @@ -128,7 +128,7 @@ func (t *CallHierarchyTool) Execute(ctx context.Context, args map[string]interfa resp := ToolResponse{ Status: "indexing_required", Message: fmt.Sprintf("⏳ Workspace '%s' is not indexed yet. Indexing is required for complete call hierarchy results.", wctx.Root), - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } if idx != nil { resp.Status = "indexing_in_progress" @@ -168,7 +168,6 @@ func (t *CallHierarchyTool) Execute(ctx context.Context, args map[string]interfa WorkspaceRoot: wctx.Root, DetectionSource: wctx.DetectionSource, Telemetry: telemetry.CalculateSavings(baselineBytes, actualBytes), - IndexingStatus: idx, }, } return resp.JSON() diff --git a/internal/service/tools/evaluate_ragcode.go b/internal/service/tools/evaluate_ragcode.go index 1d8cf2c..3e4eb02 100644 --- a/internal/service/tools/evaluate_ragcode.go +++ b/internal/service/tools/evaluate_ragcode.go @@ -130,7 +130,7 @@ func (t *EvaluateRagCodeTool) Execute(ctx context.Context, args map[string]inter Status: "success", Message: b.String(), Data: data, - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } return response.JSON() diff --git a/internal/service/tools/find_usages.go b/internal/service/tools/find_usages.go index d996de9..ac56ae6 100644 --- a/internal/service/tools/find_usages.go +++ b/internal/service/tools/find_usages.go @@ -98,7 +98,7 @@ func (t *FindUsagesTool) Execute(ctx context.Context, args map[string]interface{ resp := ToolResponse{ Status: "indexing_required", Message: fmt.Sprintf("⏳ Workspace '%s' is not indexed yet. Indexing is required for complete results.", wctx.Root), - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } if idx != nil { resp.Status = "indexing_in_progress" @@ -113,7 +113,7 @@ func (t *FindUsagesTool) Execute(ctx context.Context, args map[string]interface{ resp := ToolResponse{ Status: "success", Message: fmt.Sprintf("No usages found for symbol '%s' based on Code Graph relations.", symbolName), - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } return resp.JSON() } @@ -198,7 +198,7 @@ func (t *FindUsagesTool) Execute(ctx context.Context, args map[string]interface{ resp := ToolResponse{ Status: "success", Message: fmt.Sprintf("No explicit usages found for symbol '%s'", symbolName), - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } return resp.JSON() } @@ -256,7 +256,6 @@ func (t *FindUsagesTool) Execute(ctx context.Context, args map[string]interface{ WorkspaceRoot: wctx.Root, DetectionSource: wctx.DetectionSource, Telemetry: telemetry.CalculateSavings(baselineBytes, actualBytes), - IndexingStatus: idx, }, } return resp.JSON() diff --git a/internal/service/tools/list_package_exports.go b/internal/service/tools/list_package_exports.go index e45a0c4..539d838 100644 --- a/internal/service/tools/list_package_exports.go +++ b/internal/service/tools/list_package_exports.go @@ -113,7 +113,7 @@ func (t *ListPackageExportsTool) Execute(ctx context.Context, args map[string]in resp := ToolResponse{ Status: "indexing_required", Message: fmt.Sprintf("⏳ Workspace '%s' is not indexed yet. Indexing is required for complete results.", wctx.Root), - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } return resp.JSON() } @@ -126,7 +126,7 @@ func (t *ListPackageExportsTool) Execute(ctx context.Context, args map[string]in resp := ToolResponse{ Status: "success", Message: fmt.Sprintf("No exported symbols found in package '%s'", packageName), - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } return resp.JSON() } @@ -206,7 +206,7 @@ func (t *ListPackageExportsTool) Execute(ctx context.Context, args map[string]in resp := ToolResponse{ Status: "success", Message: fmt.Sprintf("No exported symbols found in package '%s' (after filtering)", packageName), - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } return resp.JSON() } @@ -258,7 +258,6 @@ func (t *ListPackageExportsTool) Execute(ctx context.Context, args map[string]in WorkspaceRoot: wctx.Root, DetectionSource: wctx.DetectionSource, Telemetry: telemetry.CalculateSavings(baselineBytes, actualBytes), - IndexingStatus: t.engine.GetIndexStatus(wctx.Root), }, } diff --git a/internal/service/tools/read_file_context.go b/internal/service/tools/read_file_context.go index 4fb1780..ef9166e 100644 --- a/internal/service/tools/read_file_context.go +++ b/internal/service/tools/read_file_context.go @@ -311,7 +311,7 @@ func (t *ReadFileContextTool) buildResponse(wctx *engine.WorkspaceContext, res C Message: fmt.Sprintf("Extracted %s context for lines %d-%d from %s", res.ContextType, res.StartLine, res.EndLine, res.FilePath), } if wctx != nil { - resp.Context = ContextFromWorkspaceWithStatus(wctx, t.engine) + resp.Context = ContextFromWorkspace(wctx) } baselineBytes := int64(0) diff --git a/internal/service/tools/response.go b/internal/service/tools/response.go index 11f2c12..aec33cf 100644 --- a/internal/service/tools/response.go +++ b/internal/service/tools/response.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/doITmagic/rag-code-mcp/internal/service/engine" - "github.com/doITmagic/rag-code-mcp/pkg/indexer" "github.com/doITmagic/rag-code-mcp/pkg/telemetry" ) @@ -26,7 +25,6 @@ type ContextMetadata struct { Language string `json:"language,omitempty"` Collection string `json:"collection,omitempty"` Telemetry *telemetry.Savings `json:"telemetry,omitempty"` - IndexingStatus *indexer.IndexStatus `json:"indexing_progress,omitempty"` // JSON tag kept as "indexing_progress" for backward compatibility; present when indexing is in progress or just completed SessionMetrics *telemetry.AggregatedMetrics `json:"session_metrics,omitempty"` // cumulative search stats from .ragcode/search_metrics.jsonl } @@ -57,11 +55,3 @@ func ContextFromWorkspace(wctx *engine.WorkspaceContext) ContextMetadata { } } -// ContextFromWorkspaceWithStatus builds ContextMetadata and attaches indexing status from disk. -func ContextFromWorkspaceWithStatus(wctx *engine.WorkspaceContext, eng *engine.Engine) ContextMetadata { - ctx := ContextFromWorkspace(wctx) - if eng != nil && wctx != nil { - ctx.IndexingStatus = eng.GetIndexStatus(wctx.Root) - } - return ctx -} diff --git a/internal/service/tools/skills.go b/internal/service/tools/skills.go index 4251c38..23ba260 100644 --- a/internal/service/tools/skills.go +++ b/internal/service/tools/skills.go @@ -81,7 +81,7 @@ func (t *ListSkillsTool) Execute(ctx context.Context, args map[string]interface{ response := ToolResponse{ Status: "success", - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } response.SetFallbackWarning(source == "registry_fallback") @@ -208,7 +208,7 @@ func (t *InstallSkillTool) Execute(ctx context.Context, args map[string]interfac response := ToolResponse{ Status: "success", - Context: ContextFromWorkspaceWithStatus(wctx, t.engine), + Context: ContextFromWorkspace(wctx), } response.SetFallbackWarning(source != "explicit_file_path") diff --git a/internal/service/tools/smart_search.go b/internal/service/tools/smart_search.go index cae49c1..8cd5a4d 100644 --- a/internal/service/tools/smart_search.go +++ b/internal/service/tools/smart_search.go @@ -267,7 +267,6 @@ func (t *SmartSearchTool) handleSearchError(err error, workspaceRoot, workspaceI if errors.As(err, &indexingStarted) { response.Status = "indexing_started" response.Context.WorkspaceRoot = indexingStarted.WorkspaceRoot - response.Context.IndexingStatus = t.engine.GetIndexStatus(indexingStarted.WorkspaceRoot) response.Message = fmt.Sprintf("🚀 Indexing started for workspace '%s'. Results will appear as indexing progresses.", indexingStarted.WorkspaceRoot) return response.JSON() } @@ -275,7 +274,6 @@ func (t *SmartSearchTool) handleSearchError(err error, workspaceRoot, workspaceI if errors.As(err, &indexingInProgress) { response.Status = "indexing_in_progress" response.Context.WorkspaceRoot = indexingInProgress.WorkspaceRoot - response.Context.IndexingStatus = t.engine.GetIndexStatus(indexingInProgress.WorkspaceRoot) response.Message = fmt.Sprintf("⏳ Indexing in progress for workspace '%s'. Results will improve as indexing completes.", indexingInProgress.WorkspaceRoot) return response.JSON() } diff --git a/internal/service/tools/smart_search_pipeline.go b/internal/service/tools/smart_search_pipeline.go index 4fcd258..8ff8590 100644 --- a/internal/service/tools/smart_search_pipeline.go +++ b/internal/service/tools/smart_search_pipeline.go @@ -10,7 +10,6 @@ import ( "github.com/doITmagic/rag-code-mcp/internal/logger" "github.com/doITmagic/rag-code-mcp/internal/service/engine" - "github.com/doITmagic/rag-code-mcp/pkg/indexer" "github.com/doITmagic/rag-code-mcp/pkg/scoring" "github.com/doITmagic/rag-code-mcp/pkg/telemetry" ) @@ -203,11 +202,6 @@ func applyScoreFilter(merged []mergedResult, minScore float32) []mergedResult { func (t *SmartSearchTool) buildResponseMeta(meta searchMetadata) ToolResponse { isFallback := meta.collection == "fallback" - var idxStatus *indexer.IndexStatus - if meta.workspaceRoot != "" { - idxStatus = indexer.LoadIndexStatus(meta.workspaceRoot) - } - response := ToolResponse{ Status: "success", Context: ContextMetadata{ @@ -215,7 +209,6 @@ func (t *SmartSearchTool) buildResponseMeta(meta searchMetadata) ToolResponse { DetectionSource: meta.detectionSource, Language: meta.language, Collection: meta.collection, - IndexingStatus: idxStatus, SessionMetrics: telemetry.ReadAggregatedMetrics(meta.workspaceRoot), }, }