@@ -13,21 +13,55 @@ import (
1313 "github.com/compozy/gograph/engine/core"
1414 "github.com/compozy/gograph/engine/graph"
1515 "github.com/compozy/gograph/engine/query"
16+ "github.com/compozy/gograph/pkg/config"
1617 "github.com/compozy/gograph/pkg/logger"
1718 "github.com/neo4j/neo4j-go-driver/v5/neo4j"
1819)
1920
2021// Tool handler implementations - These replace the stub implementations
2122
23+ // getProjectID extracts project ID from input, with fallback to loading from config
24+ func (s * Server ) getProjectID (input map [string ]any ) (string , error ) {
25+ // First, try to get explicit project_id
26+ if projectID , ok := input ["project_id" ].(string ); ok && projectID != "" {
27+ return projectID , nil
28+ }
29+
30+ // If not provided, try to load from project_path config
31+ projectPath , ok := input ["project_path" ].(string )
32+ if ! ok || projectPath == "" {
33+ // For tools that don't have project_path, try current directory
34+ cwd , err := os .Getwd ()
35+ if err != nil {
36+ return "" , fmt .Errorf ("project_id not provided and cannot determine current directory: %w" , err )
37+ }
38+ projectPath = cwd
39+ }
40+
41+ // Try to load from config
42+ cfg , err := config .LoadProjectConfig (projectPath )
43+ if err != nil {
44+ return "" , fmt .Errorf ("project_id not provided and failed to load config from %s: %w" , projectPath , err )
45+ }
46+
47+ if cfg .Project .ID == "" {
48+ return "" , fmt .Errorf ("project_id not provided and not found in config at %s" , projectPath )
49+ }
50+
51+ return cfg .Project .ID , nil
52+ }
53+
2254// HandleAnalyzeProjectInternal analyzes a Go project and stores results in Neo4j
2355func (s * Server ) HandleAnalyzeProjectInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
2456 projectPath , ok := input ["project_path" ].(string )
2557 if ! ok {
2658 return nil , fmt .Errorf ("project_path is required" )
2759 }
28- projectID , ok := input ["project_id" ].(string )
29- if ! ok {
30- return nil , fmt .Errorf ("project_id is required" )
60+
61+ // Get project ID using helper
62+ projectID , err := s .getProjectID (input )
63+ if err != nil {
64+ return nil , err
3165 }
3266
3367 // Validate path is allowed
@@ -108,10 +142,12 @@ func (s *Server) HandleAnalyzeProjectInternal(ctx context.Context, input map[str
108142
109143// HandleExecuteCypherInternal executes a custom Cypher query
110144func (s * Server ) HandleExecuteCypherInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
111- projectID , ok := input ["project_id" ].(string )
112- if ! ok {
113- return nil , fmt .Errorf ("project_id is required" )
145+ // Get project ID using helper
146+ projectID , err := s .getProjectID (input )
147+ if err != nil {
148+ return nil , err
114149 }
150+
115151 query , ok := input ["query" ].(string )
116152 if ! ok {
117153 return nil , fmt .Errorf ("query is required" )
@@ -161,9 +197,10 @@ func (s *Server) HandleExecuteCypherInternal(ctx context.Context, input map[stri
161197//
162198//nolint:funlen,gocyclo // MCP tool handlers can be longer and have complex logic
163199func (s * Server ) HandleGetFunctionInfoInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
164- projectID , ok := input ["project_id" ].(string )
165- if ! ok {
166- return nil , fmt .Errorf ("project_id is required" )
200+ // Get project ID using helper
201+ projectID , err := s .getProjectID (input )
202+ if err != nil {
203+ return nil , err
167204 }
168205 functionName , ok := input ["function_name" ].(string )
169206 if ! ok {
@@ -343,9 +380,10 @@ func (s *Server) AddFunctionRelationships(
343380//
344381//nolint:funlen // MCP tool handlers can be longer for comprehensive functionality
345382func (s * Server ) HandleQueryDependenciesInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
346- projectID , ok := input ["project_id" ].(string )
347- if ! ok {
348- return nil , fmt .Errorf ("project_id is required" )
383+ // Get project ID using helper
384+ projectID , err := s .getProjectID (input )
385+ if err != nil {
386+ return nil , err
349387 }
350388 path , ok := input ["path" ].(string )
351389 if ! ok {
@@ -489,9 +527,10 @@ func (s *Server) IsPathAllowed(path string) bool {
489527//
490528//nolint:funlen // MCP tool handlers can be longer for comprehensive functionality
491529func (s * Server ) HandleFindImplementationsInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
492- projectID , ok := input ["project_id" ].(string )
493- if ! ok {
494- return nil , fmt .Errorf ("project_id is required" )
530+ // Get project ID using helper
531+ projectID , err := s .getProjectID (input )
532+ if err != nil {
533+ return nil , err
495534 }
496535 interfaceName , ok := input ["interface_name" ].(string )
497536 if ! ok {
@@ -578,9 +617,10 @@ func (s *Server) HandleFindImplementationsInternal(ctx context.Context, input ma
578617//
579618//nolint:funlen // MCP tool handlers can be longer for comprehensive functionality
580619func (s * Server ) HandleTraceCallChainInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
581- projectID , ok := input ["project_id" ].(string )
582- if ! ok {
583- return nil , fmt .Errorf ("project_id is required" )
620+ // Get project ID using helper
621+ projectID , err := s .getProjectID (input )
622+ if err != nil {
623+ return nil , err
584624 }
585625 fromFunction , ok := input ["from_function" ].(string )
586626 if ! ok {
@@ -682,9 +722,10 @@ func (s *Server) HandleTraceCallChainInternal(ctx context.Context, input map[str
682722
683723// handleDetectCircularDeps detects circular dependencies
684724func (s * Server ) HandleDetectCircularDepsInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
685- projectID , ok := input ["project_id" ].(string )
686- if ! ok {
687- return nil , fmt .Errorf ("project_id is required" )
725+ // Get project ID using helper
726+ projectID , err := s .getProjectID (input )
727+ if err != nil {
728+ return nil , err
688729 }
689730 scope := "packages"
690731 if s , ok := input ["scope" ].(string ); ok {
@@ -745,9 +786,10 @@ func (s *Server) HandleDetectCircularDepsInternal(ctx context.Context, input map
745786
746787// handleListPackages lists all packages in the project
747788func (s * Server ) HandleListPackagesInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
748- projectID , ok := input ["project_id" ].(string )
749- if ! ok {
750- return nil , fmt .Errorf ("project_id is required" )
789+ // Get project ID using helper
790+ projectID , err := s .getProjectID (input )
791+ if err != nil {
792+ return nil , err
751793 }
752794 pattern := ""
753795 if p , ok := input ["pattern" ].(string ); ok {
@@ -810,9 +852,10 @@ func (s *Server) HandleListPackagesInternal(ctx context.Context, input map[strin
810852//
811853//nolint:funlen // MCP tool handlers can be longer for comprehensive functionality
812854func (s * Server ) HandleGetPackageStructureInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
813- projectID , ok := input ["project_id" ].(string )
814- if ! ok {
815- return nil , fmt .Errorf ("project_id is required" )
855+ // Get project ID using helper
856+ projectID , err := s .getProjectID (input )
857+ if err != nil {
858+ return nil , err
816859 }
817860 packageName , ok := input ["package" ].(string )
818861 if ! ok {
@@ -915,9 +958,10 @@ func (s *Server) HandleGetPackageStructureInternal(ctx context.Context, input ma
915958
916959// handleNaturalLanguageQuery converts natural language to Cypher and executes
917960func (s * Server ) HandleNaturalLanguageQueryInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
918- projectID , ok := input ["project_id" ].(string )
919- if ! ok {
920- return nil , fmt .Errorf ("project_id is required" )
961+ // Get project ID using helper
962+ projectID , err := s .getProjectID (input )
963+ if err != nil {
964+ return nil , err
921965 }
922966 query , ok := input ["query" ].(string )
923967 if ! ok {
@@ -936,7 +980,6 @@ func (s *Server) HandleNaturalLanguageQueryInternal(ctx context.Context, input m
936980 // Use LLM service to translate natural language to Cypher
937981 var cypherQuery string
938982 var params map [string ]any
939- var err error
940983
941984 if s .llmService != nil {
942985 // Get schema for the project
@@ -994,9 +1037,10 @@ func (s *Server) HandleNaturalLanguageQueryInternal(ctx context.Context, input m
9941037//
9951038//nolint:gocyclo,funlen // MCP tool handlers need multiple branches for different element types
9961039func (s * Server ) HandleVerifyCodeExistsInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
997- projectID , ok := input ["project_id" ].(string )
998- if ! ok {
999- return nil , fmt .Errorf ("project_id is required" )
1040+ // Get project ID using helper
1041+ projectID , err := s .getProjectID (input )
1042+ if err != nil {
1043+ return nil , err
10001044 }
10011045 elementType , ok := input ["element_type" ].(string )
10021046 if ! ok {
@@ -1374,11 +1418,12 @@ func (s *Server) BuildElementLocationQuery(elementType string) (string, error) {
13741418func (s * Server ) ParseCodeContextInput (
13751419 input map [string ]any ,
13761420) (projectID , elementType , name string , contextLines int , err error ) {
1377- projectID , ok := input ["project_id" ].(string )
1378- if ! ok {
1379- return "" , "" , "" , 0 , fmt .Errorf ("project_id is required" )
1421+ // Get project ID using helper
1422+ projectID , err = s .getProjectID (input )
1423+ if err != nil {
1424+ return "" , "" , "" , 0 , err
13801425 }
1381- elementType , ok = input ["element_type" ].(string )
1426+ elementType , ok : = input ["element_type" ].(string )
13821427 if ! ok {
13831428 return "" , "" , "" , 0 , fmt .Errorf ("element_type is required" )
13841429 }
@@ -1507,9 +1552,10 @@ func (s *Server) ExtractCodeContextFromResults(
15071552
15081553// handleValidateImportPath validates an import path
15091554func (s * Server ) HandleValidateImportPathInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
1510- projectID , ok := input ["project_id" ].(string )
1511- if ! ok {
1512- return nil , fmt .Errorf ("project_id is required" )
1555+ // Get project ID using helper
1556+ projectID , err := s .getProjectID (input )
1557+ if err != nil {
1558+ return nil , err
15131559 }
15141560 importPath , ok := input ["import_path" ].(string )
15151561 if ! ok {
@@ -1594,9 +1640,10 @@ func (s *Server) HandleValidateImportPathInternal(ctx context.Context, input map
15941640
15951641// handleDetectCodePatterns detects code patterns
15961642func (s * Server ) HandleDetectCodePatternsInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
1597- projectID , ok := input ["project_id" ].(string )
1598- if ! ok {
1599- return nil , fmt .Errorf ("project_id is required" )
1643+ // Get project ID using helper
1644+ projectID , err := s .getProjectID (input )
1645+ if err != nil {
1646+ return nil , err
16001647 }
16011648 // Extract patterns filter (optional)
16021649 _ = input ["patterns" ] // TODO: Use specific patterns filter in future
@@ -1635,9 +1682,10 @@ func (s *Server) HandleDetectCodePatternsInternal(ctx context.Context, input map
16351682
16361683// handleGetNamingConventions analyzes naming conventions
16371684func (s * Server ) HandleGetNamingConventionsInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
1638- projectID , ok := input ["project_id" ].(string )
1639- if ! ok {
1640- return nil , fmt .Errorf ("project_id is required" )
1685+ // Get project ID using helper
1686+ projectID , err := s .getProjectID (input )
1687+ if err != nil {
1688+ return nil , err
16411689 }
16421690 scope := ""
16431691 if s , ok := input ["scope" ].(string ); ok {
@@ -1685,9 +1733,10 @@ func (s *Server) HandleGetNamingConventionsInternal(ctx context.Context, input m
16851733
16861734// handleFindTestsForCode finds tests for code elements
16871735func (s * Server ) HandleFindTestsForCodeInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
1688- projectID , ok := input ["project_id" ].(string )
1689- if ! ok {
1690- return nil , fmt .Errorf ("project_id is required" )
1736+ // Get project ID using helper
1737+ projectID , err := s .getProjectID (input )
1738+ if err != nil {
1739+ return nil , err
16911740 }
16921741 elementType , ok := input ["element_type" ].(string )
16931742 if ! ok {
@@ -1738,9 +1787,10 @@ func (s *Server) HandleFindTestsForCodeInternal(ctx context.Context, input map[s
17381787
17391788// handleCheckTestCoverage checks test coverage
17401789func (s * Server ) HandleCheckTestCoverageInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
1741- projectID , ok := input ["project_id" ].(string )
1742- if ! ok {
1743- return nil , fmt .Errorf ("project_id is required" )
1790+ // Get project ID using helper
1791+ projectID , err := s .getProjectID (input )
1792+ if err != nil {
1793+ return nil , err
17441794 }
17451795 path := ""
17461796 if p , ok := input ["path" ].(string ); ok {
@@ -2523,9 +2573,10 @@ func (s *Server) HandleListProjectsInternal(ctx context.Context, _ map[string]an
25232573
25242574// HandleValidateProjectInternal validates if a project exists in the database
25252575func (s * Server ) HandleValidateProjectInternal (ctx context.Context , input map [string ]any ) (* ToolResponse , error ) {
2526- projectID , ok := input ["project_id" ].(string )
2527- if ! ok {
2528- return nil , fmt .Errorf ("project_id is required" )
2576+ // Get project ID using helper
2577+ projectID , err := s .getProjectID (input )
2578+ if err != nil {
2579+ return nil , err
25292580 }
25302581
25312582 logger .Info ("validating project existence" , "project_id" , projectID )
0 commit comments