4
4
from pydantic import Field
5
5
import json
6
6
from enum import Enum
7
+ import argparse
8
+ import os
9
+ import sys
10
+
11
+ # Determine how the script was invoked
12
+ if sys .argv [0 ].endswith ('main.py' ):
13
+ # Direct execution: python main.py
14
+ prog = 'python main.py'
15
+ else :
16
+ # Installed script execution (via uvx, pip install, etc.)
17
+ prog = None # Let argparse use the default
18
+
19
+ # Parse command-line arguments
20
+ parser = argparse .ArgumentParser (
21
+ prog = prog ,
22
+ description = 'ast-grep MCP Server - Provides structural code search capabilities via Model Context Protocol' ,
23
+ epilog = '''
24
+ environment variables:
25
+ AST_GREP_CONFIG Path to sgconfig.yaml file (overridden by --config flag)
26
+
27
+ For more information, see: https://github.com/ast-grep/ast-grep-mcp
28
+ ''' ,
29
+ formatter_class = argparse .RawDescriptionHelpFormatter
30
+ )
31
+ parser .add_argument (
32
+ '--config' ,
33
+ type = str ,
34
+ metavar = 'PATH' ,
35
+ help = 'Path to sgconfig.yaml file for customizing ast-grep behavior (language mappings, rule directories, etc.)'
36
+ )
37
+ args = parser .parse_args ()
38
+
39
+ # Determine config path with precedence: --config flag > AST_GREP_CONFIG env > None
40
+ CONFIG_PATH = None
41
+ if args .config :
42
+ if not os .path .exists (args .config ):
43
+ print (f"Error: Config file '{ args .config } ' does not exist" )
44
+ sys .exit (1 )
45
+ CONFIG_PATH = args .config
46
+ elif os .environ .get ('AST_GREP_CONFIG' ):
47
+ env_config = os .environ .get ('AST_GREP_CONFIG' )
48
+ if not os .path .exists (env_config ):
49
+ print (f"Error: Config file '{ env_config } ' specified in AST_GREP_CONFIG does not exist" )
50
+ sys .exit (1 )
51
+ CONFIG_PATH = env_config
7
52
8
53
# Initialize FastMCP server
9
54
mcp = FastMCP ("ast-grep" )
@@ -40,6 +85,8 @@ def test_match_code_rule(
40
85
This is useful to test a rule before using it in a project.
41
86
"""
42
87
args = ["ast-grep" , "scan" ,"--inline-rules" , yaml , "--json" , "--stdin" ]
88
+ if CONFIG_PATH :
89
+ args .extend (["--config" , CONFIG_PATH ])
43
90
try :
44
91
# Run command and capture output
45
92
result = subprocess .run (
@@ -82,7 +129,9 @@ def find_code_by_rule(
82
129
return run_ast_grep_yaml (yaml , project_folder )
83
130
84
131
def run_ast_grep_dump (code : str , language : str , format : str ) -> str :
85
- args = ["ast-grep" , "--pattern" , code , "--lang" , language , f"--debug-query={ format } " ]
132
+ args = ["ast-grep" , "run" , "--pattern" , code , "--lang" , language , f"--debug-query={ format } " ]
133
+ if CONFIG_PATH :
134
+ args .extend (["--config" , CONFIG_PATH ])
86
135
try :
87
136
result = subprocess .run (
88
137
args ,
@@ -98,9 +147,12 @@ def run_ast_grep_dump(code: str, language: str, format: str) -> str:
98
147
99
148
def run_ast_grep_command (pattern : str , project_folder : str , language : Optional [str ]) -> List [dict [str , Any ]]:
100
149
try :
101
- args = ["ast-grep" , "--pattern" , pattern , "--json" , project_folder ]
150
+ args = ["ast-grep" , "run" , "--pattern" , pattern , "--json" ]
151
+ if CONFIG_PATH :
152
+ args .extend (["--config" , CONFIG_PATH ])
102
153
if language :
103
154
args .extend (["--lang" , language ])
155
+ args .append (project_folder )
104
156
# Run command and capture output
105
157
result = subprocess .run (
106
158
args ,
@@ -120,6 +172,8 @@ def run_ast_grep_command(pattern: str, project_folder: str, language: Optional[s
120
172
def run_ast_grep_yaml (yaml : str , project_folder : str ) -> List [dict [str , Any ]]:
121
173
try :
122
174
args = ["ast-grep" , "scan" ,"--inline-rules" , yaml , "--json" , project_folder ]
175
+ if CONFIG_PATH :
176
+ args .extend (["--config" , CONFIG_PATH ])
123
177
# Run command and capture output
124
178
result = subprocess .run (
125
179
args ,
0 commit comments