1212from pathlib import Path
1313
1414# Add src to path so we can import mcpm modules
15- sys .path .insert (0 , os .path .join (os .path .dirname (__file__ ), '..' , ' src' ))
15+ sys .path .insert (0 , os .path .join (os .path .dirname (__file__ ), ".." , " src" ))
1616
1717import click
18+
1819from mcpm .cli import main as mcpm_cli
1920
2021# Try to import version, fallback to a default if not available
2728def extract_command_info (cmd , parent_name = "" ):
2829 """Extract information from a Click command."""
2930 info = {
30- ' name' : cmd .name ,
31- ' full_name' : f"{ parent_name } { cmd .name } " .strip (),
32- ' help' : cmd .help or "No description available" ,
33- ' params' : [],
34- ' subcommands' : {}
31+ " name" : cmd .name ,
32+ " full_name" : f"{ parent_name } { cmd .name } " .strip (),
33+ " help" : cmd .help or "No description available" ,
34+ " params" : [],
35+ " subcommands" : {}
3536 }
36-
37+
3738 # Extract parameters
3839 for param in cmd .params :
3940 param_info = {
40- ' name' : param .name ,
41- ' opts' : getattr (param , ' opts' , None ) or [param .name ],
42- ' type' : str (param .type ),
43- ' help' : getattr (param , ' help' , "" ) or "" ,
44- ' required' : getattr (param , ' required' , False ),
45- ' is_flag' : isinstance (param , click .Option ) and param .is_flag ,
46- ' default' : getattr (param , ' default' , None )
41+ " name" : param .name ,
42+ " opts" : getattr (param , " opts" , None ) or [param .name ],
43+ " type" : str (param .type ),
44+ " help" : getattr (param , " help" , "" ) or "" ,
45+ " required" : getattr (param , " required" , False ),
46+ " is_flag" : isinstance (param , click .Option ) and param .is_flag ,
47+ " default" : getattr (param , " default" , None )
4748 }
48- info [' params' ].append (param_info )
49-
49+ info [" params" ].append (param_info )
50+
5051 # Extract subcommands if this is a group
5152 if isinstance (cmd , click .Group ):
5253 for subcommand_name , subcommand in cmd .commands .items ():
53- info [' subcommands' ][subcommand_name ] = extract_command_info (
54- subcommand ,
55- info [' full_name' ]
54+ info [" subcommands" ][subcommand_name ] = extract_command_info (
55+ subcommand ,
56+ info [" full_name" ]
5657 )
57-
58+
5859 return info
5960
6061
6162def format_command_section (cmd_info , level = 2 ):
6263 """Format a command's information for the LLM.txt file."""
6364 lines = []
64-
65+
6566 # Command header
6667 header = "#" * level + f" { cmd_info ['full_name' ]} "
6768 lines .append (header )
6869 lines .append ("" )
69-
70+
7071 # Description
71- lines .append (cmd_info [' help' ])
72+ lines .append (cmd_info [" help" ])
7273 lines .append ("" )
73-
74+
7475 # Parameters
75- if cmd_info [' params' ]:
76+ if cmd_info [" params" ]:
7677 lines .append ("**Parameters:**" )
7778 lines .append ("" )
78-
79+
7980 # Separate arguments from options
80- args = [p for p in cmd_info [' params' ] if not p [' opts' ][0 ].startswith ('-' )]
81- opts = [p for p in cmd_info [' params' ] if p [' opts' ][0 ].startswith ('-' )]
82-
81+ args = [p for p in cmd_info [" params" ] if not p [" opts" ][0 ].startswith ("-" )]
82+ opts = [p for p in cmd_info [" params" ] if p [" opts" ][0 ].startswith ("-" )]
83+
8384 if args :
8485 for param in args :
85- req = "REQUIRED" if param [' required' ] else "OPTIONAL"
86+ req = "REQUIRED" if param [" required" ] else "OPTIONAL"
8687 lines .append (f"- `{ param ['name' ]} ` ({ req } ): { param ['help' ]} " )
8788 lines .append ("" )
88-
89+
8990 if opts :
9091 for param in opts :
91- opt_str = ", " .join (f"`{ opt } `" for opt in param [' opts' ])
92- if param [' is_flag' ]:
92+ opt_str = ", " .join (f"`{ opt } `" for opt in param [" opts" ])
93+ if param [" is_flag" ]:
9394 lines .append (f"- { opt_str } : { param ['help' ]} (flag)" )
9495 else :
95- default_str = f" (default: { param ['default' ]} )" if param [' default' ] is not None else ""
96+ default_str = f" (default: { param ['default' ]} )" if param [" default" ] is not None else ""
9697 lines .append (f"- { opt_str } : { param ['help' ]} { default_str } " )
9798 lines .append ("" )
98-
99+
99100 # Examples section
100101 examples = generate_examples_for_command (cmd_info )
101102 if examples :
@@ -105,101 +106,100 @@ def format_command_section(cmd_info, level=2):
105106 lines .extend (examples )
106107 lines .append ("```" )
107108 lines .append ("" )
108-
109+
109110 # Subcommands
110- for subcmd_info in cmd_info [' subcommands' ].values ():
111+ for subcmd_info in cmd_info [" subcommands" ].values ():
111112 lines .extend (format_command_section (subcmd_info , level + 1 ))
112-
113+
113114 return lines
114115
115116
116117def generate_examples_for_command (cmd_info ):
117118 """Generate relevant examples for a command based on its name and parameters."""
118- examples = []
119- cmd = cmd_info ['full_name' ]
120-
119+ cmd = cmd_info ["full_name" ]
120+
121121 # Map of command patterns to example sets
122122 example_map = {
123- ' mcpm new' : [
124- ' # Create a stdio server' ,
123+ " mcpm new" : [
124+ " # Create a stdio server" ,
125125 'mcpm new myserver --type stdio --command "python -m myserver"' ,
126- '' ,
127- ' # Create a remote server' ,
126+ "" ,
127+ " # Create a remote server" ,
128128 'mcpm new apiserver --type remote --url "https://api.example.com"' ,
129- '' ,
130- ' # Create server with environment variables' ,
129+ "" ,
130+ " # Create server with environment variables" ,
131131 'mcpm new myserver --type stdio --command "python server.py" --env "API_KEY=secret,PORT=8080"' ,
132132 ],
133- ' mcpm edit' : [
134- ' # Update server name' ,
133+ " mcpm edit" : [
134+ " # Update server name" ,
135135 'mcpm edit myserver --name "new-name"' ,
136- '' ,
137- ' # Update command and arguments' ,
136+ "" ,
137+ " # Update command and arguments" ,
138138 'mcpm edit myserver --command "python -m updated_server" --args "--port 8080"' ,
139- '' ,
140- ' # Update environment variables' ,
139+ "" ,
140+ " # Update environment variables" ,
141141 'mcpm edit myserver --env "API_KEY=new-secret,DEBUG=true"' ,
142142 ],
143- ' mcpm install' : [
144- ' # Install a server' ,
145- ' mcpm install sqlite' ,
146- '' ,
147- ' # Install with environment variables' ,
148- ' ANTHROPIC_API_KEY=sk-ant-... mcpm install claude' ,
149- '' ,
150- ' # Force installation' ,
151- ' mcpm install filesystem --force' ,
143+ " mcpm install" : [
144+ " # Install a server" ,
145+ " mcpm install sqlite" ,
146+ "" ,
147+ " # Install with environment variables" ,
148+ " ANTHROPIC_API_KEY=sk-ant-... mcpm install claude" ,
149+ "" ,
150+ " # Force installation" ,
151+ " mcpm install filesystem --force" ,
152152 ],
153- ' mcpm profile edit' : [
154- ' # Add server to profile' ,
155- ' mcpm profile edit web-dev --add-server sqlite' ,
156- '' ,
157- ' # Remove server from profile' ,
158- ' mcpm profile edit web-dev --remove-server old-server' ,
159- '' ,
160- ' # Set profile servers (replaces all)' ,
153+ " mcpm profile edit" : [
154+ " # Add server to profile" ,
155+ " mcpm profile edit web-dev --add-server sqlite" ,
156+ "" ,
157+ " # Remove server from profile" ,
158+ " mcpm profile edit web-dev --remove-server old-server" ,
159+ "" ,
160+ " # Set profile servers (replaces all)" ,
161161 'mcpm profile edit web-dev --set-servers "sqlite,filesystem,git"' ,
162- '' ,
163- ' # Rename profile' ,
164- ' mcpm profile edit old-name --name new-name' ,
162+ "" ,
163+ " # Rename profile" ,
164+ " mcpm profile edit old-name --name new-name" ,
165165 ],
166- ' mcpm client edit' : [
167- ' # Add server to client' ,
168- ' mcpm client edit cursor --add-server sqlite' ,
169- '' ,
170- ' # Add profile to client' ,
171- ' mcpm client edit cursor --add-profile web-dev' ,
172- '' ,
173- ' # Set all servers for client' ,
166+ " mcpm client edit" : [
167+ " # Add server to client" ,
168+ " mcpm client edit cursor --add-server sqlite" ,
169+ "" ,
170+ " # Add profile to client" ,
171+ " mcpm client edit cursor --add-profile web-dev" ,
172+ "" ,
173+ " # Set all servers for client" ,
174174 'mcpm client edit claude-desktop --set-servers "sqlite,filesystem"' ,
175- '' ,
176- ' # Remove profile from client' ,
177- ' mcpm client edit cursor --remove-profile old-profile' ,
175+ "" ,
176+ " # Remove profile from client" ,
177+ " mcpm client edit cursor --remove-profile old-profile" ,
178178 ],
179- ' mcpm run' : [
180- ' # Run a server' ,
181- ' mcpm run sqlite' ,
182- '' ,
183- ' # Run with HTTP transport' ,
184- ' mcpm run myserver --http --port 8080' ,
179+ " mcpm run" : [
180+ " # Run a server" ,
181+ " mcpm run sqlite" ,
182+ "" ,
183+ " # Run with HTTP transport" ,
184+ " mcpm run myserver --http --port 8080" ,
185185 ],
186- ' mcpm profile run' : [
187- ' # Run all servers in a profile' ,
188- ' mcpm profile run web-dev' ,
189- '' ,
190- ' # Run profile with custom port' ,
191- ' mcpm profile run web-dev --port 8080 --http' ,
186+ " mcpm profile run" : [
187+ " # Run all servers in a profile" ,
188+ " mcpm profile run web-dev" ,
189+ "" ,
190+ " # Run profile with custom port" ,
191+ " mcpm profile run web-dev --port 8080 --http" ,
192192 ],
193193 }
194-
194+
195195 # Return examples if we have them for this command
196196 if cmd in example_map :
197197 return example_map [cmd ]
198-
198+
199199 # Generate basic example if no specific examples
200- if cmd_info [' params' ]:
201- return [f "# Basic usage" , f"{ cmd } <arguments>" ]
202-
200+ if cmd_info [" params" ]:
201+ return ["# Basic usage" , f"{ cmd } <arguments>" ]
202+
203203 return []
204204
205205
@@ -241,15 +241,15 @@ def generate_llm_txt():
241241 "## Command Reference" ,
242242 "" ,
243243 ]
244-
244+
245245 # Extract command structure
246246 cmd_info = extract_command_info (mcpm_cli )
247-
247+
248248 # Format main commands
249- for subcmd_name in sorted (cmd_info [' subcommands' ].keys ()):
250- subcmd_info = cmd_info [' subcommands' ][subcmd_name ]
249+ for subcmd_name in sorted (cmd_info [" subcommands" ].keys ()):
250+ subcmd_info = cmd_info [" subcommands" ][subcmd_name ]
251251 lines .extend (format_command_section (subcmd_info ))
252-
252+
253253 # Add best practices section
254254 lines .extend ([
255255 "## Best Practices for AI Agents" ,
@@ -318,10 +318,10 @@ def generate_llm_txt():
318318 "" ,
319319 "```bash" ,
320320 "# Add multiple servers at once" ,
321- " mcpm profile edit myprofile --add-server \ " server1,server2,server3\" " ,
321+ ' mcpm profile edit myprofile --add-server "server1,server2,server3"' ,
322322 "" ,
323323 "# Remove multiple servers" ,
324- " mcpm client edit cursor --remove-server \ " old1,old2\" " ,
324+ ' mcpm client edit cursor --remove-server "old1,old2"' ,
325325 "```" ,
326326 "" ,
327327 "### Using Environment Variables for Secrets" ,
@@ -374,27 +374,27 @@ def generate_llm_txt():
374374 "- Use `mcpm doctor` to diagnose system issues" ,
375375 "" ,
376376 ])
377-
377+
378378 return "\n " .join (lines )
379379
380380
381381def main ():
382382 """Generate and save the LLM.txt file."""
383383 content = generate_llm_txt ()
384-
384+
385385 # Determine output path
386386 script_dir = Path (__file__ ).parent
387387 project_root = script_dir .parent
388388 output_path = project_root / "llm.txt"
389-
389+
390390 # Write the file
391- with open (output_path , 'w' , encoding = ' utf-8' ) as f :
391+ with open (output_path , "w" , encoding = " utf-8" ) as f :
392392 f .write (content )
393-
393+
394394 print (f"✅ Generated llm.txt at: { output_path } " )
395395 print (f"📄 File size: { len (content ):,} bytes" )
396396 print (f"📝 Lines: { content .count (chr (10 )):,} " )
397397
398398
399399if __name__ == "__main__" :
400- main ()
400+ main ()
0 commit comments