fips-agents-cli 0.1.9__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/.github/workflows/test.yml +2 -0
  2. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/.github/workflows/workflow.yaml +1 -1
  3. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/PKG-INFO +17 -1
  4. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/README.md +16 -0
  5. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/pyproject.toml +1 -1
  6. fips_agents_cli-0.2.0/src/fips_agents_cli/commands/create.py +447 -0
  7. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/commands/patch.py +15 -0
  8. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/git.py +60 -0
  9. fips_agents_cli-0.2.0/src/fips_agents_cli/tools/github.py +193 -0
  10. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/project.py +12 -0
  11. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/version.py +1 -1
  12. fips_agents_cli-0.2.0/tests/test_create.py +559 -0
  13. fips_agents_cli-0.2.0/tests/test_github.py +274 -0
  14. fips_agents_cli-0.1.9/src/fips_agents_cli/commands/create.py +0 -192
  15. fips_agents_cli-0.1.9/tests/test_create.py +0 -193
  16. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/.claude/commands/create-release.md +0 -0
  17. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/.github/agents/README.md +0 -0
  18. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/.github/agents/create-release.agent.md +0 -0
  19. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/.gitignore +0 -0
  20. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/AGENT_FRAMEWORK_PLAN.md +0 -0
  21. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/BAML_RESEARCH_REPORT.md +0 -0
  22. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/CLAUDE.md +0 -0
  23. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/GENERATOR_IMPLEMENTATION_PLAN.md +0 -0
  24. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/IMPLEMENTATION_SUMMARY.md +0 -0
  25. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/Ignite-CLI-Architecture-Analysis.md +0 -0
  26. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/LICENSE +0 -0
  27. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/MVP-PLAN.md +0 -0
  28. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/PLAN.md +0 -0
  29. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/PROMPT_ISSUE.md +0 -0
  30. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/PUBLISHING.md +0 -0
  31. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/QUICK_START_PUBLISHING.md +0 -0
  32. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/RELEASE_CHECKLIST.md +0 -0
  33. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/scripts/README.md +0 -0
  34. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/scripts/release.sh +0 -0
  35. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/__init__.py +0 -0
  36. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/__main__.py +0 -0
  37. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/cli.py +0 -0
  38. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/commands/__init__.py +0 -0
  39. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/commands/generate.py +0 -0
  40. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/commands/model_car.py +0 -0
  41. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/__init__.py +0 -0
  42. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/filesystem.py +0 -0
  43. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/generators.py +0 -0
  44. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/patching.py +0 -0
  45. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/validation.py +0 -0
  46. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/tests/__init__.py +0 -0
  47. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/tests/conftest.py +0 -0
  48. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/tests/test_filesystem.py +0 -0
  49. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/tests/test_generate.py +0 -0
  50. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/tests/test_generators.py +0 -0
  51. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/tests/test_model_car.py +0 -0
  52. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/tests/test_project.py +0 -0
  53. {fips_agents_cli-0.1.9 → fips_agents_cli-0.2.0}/tests/test_validation.py +0 -0
@@ -3,6 +3,8 @@ name: Tests
3
3
  on:
4
4
  push:
5
5
  branches: [ main ]
6
+ tags:
7
+ - 'v*.*.*'
6
8
  pull_request:
7
9
  branches: [ main ]
8
10
 
@@ -21,7 +21,7 @@ jobs:
21
21
  uses: lewagon/wait-on-check-action@v1.3.1
22
22
  with:
23
23
  ref: ${{ github.ref }}
24
- check-name: 'Tests Status'
24
+ check-regexp: 'Test on Python'
25
25
  repo-token: ${{ secrets.GITHUB_TOKEN }}
26
26
  wait-interval: 10
27
27
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fips-agents-cli
3
- Version: 0.1.9
3
+ Version: 0.2.0
4
4
  Summary: CLI tool for creating and managing FIPS-compliant AI agent projects
5
5
  Project-URL: Homepage, https://github.com/rdwj/fips-agents-cli
6
6
  Project-URL: Repository, https://github.com/rdwj/fips-agents-cli
@@ -528,6 +528,22 @@ MIT License - see LICENSE file for details
528
528
 
529
529
  ## Changelog
530
530
 
531
+ ### Version 0.2.0
532
+
533
+ - Feature: GitHub integration for `create mcp-server` command
534
+ - Feature: New `--github` flag to create GitHub repository and push code
535
+ - Feature: New `--local` flag to skip GitHub and create local-only project
536
+ - Feature: Non-interactive mode (`--yes`) for agent/CI workflows
537
+ - Feature: New `--private` flag to create private GitHub repositories
538
+ - Feature: New `--org` option to create repositories in GitHub organizations
539
+ - Feature: New `--description` option for GitHub repository descriptions
540
+ - Feature: New `--remote-only` flag to create GitHub repo without local clone
541
+ - Feature: Added missing `patch build` subcommand for updating build/deployment files
542
+ - Feature: GitHub metadata tracking in `.template-info` file
543
+ - Feature: New git utilities for remote management (`add_remote`, `push_to_remote`)
544
+ - Improvement: Auto-detects `gh` CLI and prompts user when available
545
+ - Improvement: Clean git history - customizes project before initial push
546
+
531
547
  ### Version 0.1.9
532
548
 
533
549
  - Feature: Added `.fips-agents-cli` directory to ModelCar projects with generation metadata
@@ -495,6 +495,22 @@ MIT License - see LICENSE file for details
495
495
 
496
496
  ## Changelog
497
497
 
498
+ ### Version 0.2.0
499
+
500
+ - Feature: GitHub integration for `create mcp-server` command
501
+ - Feature: New `--github` flag to create GitHub repository and push code
502
+ - Feature: New `--local` flag to skip GitHub and create local-only project
503
+ - Feature: Non-interactive mode (`--yes`) for agent/CI workflows
504
+ - Feature: New `--private` flag to create private GitHub repositories
505
+ - Feature: New `--org` option to create repositories in GitHub organizations
506
+ - Feature: New `--description` option for GitHub repository descriptions
507
+ - Feature: New `--remote-only` flag to create GitHub repo without local clone
508
+ - Feature: Added missing `patch build` subcommand for updating build/deployment files
509
+ - Feature: GitHub metadata tracking in `.template-info` file
510
+ - Feature: New git utilities for remote management (`add_remote`, `push_to_remote`)
511
+ - Improvement: Auto-detects `gh` CLI and prompts user when available
512
+ - Improvement: Clean git history - customizes project before initial push
513
+
498
514
  ### Version 0.1.9
499
515
 
500
516
  - Feature: Added `.fips-agents-cli` directory to ModelCar projects with generation metadata
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "fips-agents-cli"
7
- version = "0.1.9"
7
+ version = "0.2.0"
8
8
  description = "CLI tool for creating and managing FIPS-compliant AI agent projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,447 @@
1
+ """Create command for generating new projects from templates."""
2
+
3
+ import sys
4
+
5
+ import click
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+ from rich.progress import Progress, SpinnerColumn, TextColumn
9
+
10
+ from fips_agents_cli.commands.model_car import model_car
11
+ from fips_agents_cli.tools.filesystem import resolve_target_path, validate_target_directory
12
+ from fips_agents_cli.tools.git import (
13
+ add_remote,
14
+ clone_template,
15
+ init_repository,
16
+ is_git_installed,
17
+ push_to_remote,
18
+ )
19
+ from fips_agents_cli.tools.github import (
20
+ check_gh_prerequisites,
21
+ create_github_repo,
22
+ get_github_username,
23
+ is_gh_authenticated,
24
+ is_gh_installed,
25
+ )
26
+ from fips_agents_cli.tools.project import (
27
+ cleanup_template_files,
28
+ to_module_name,
29
+ update_project_name,
30
+ validate_project_name,
31
+ write_template_info,
32
+ )
33
+
34
+ console = Console()
35
+
36
+ # Template URL for MCP server projects
37
+ MCP_SERVER_TEMPLATE_URL = "https://github.com/rdwj/mcp-server-template"
38
+
39
+
40
+ @click.group()
41
+ def create():
42
+ """Create new projects from templates."""
43
+ pass
44
+
45
+
46
+ # Register subcommands
47
+ create.add_command(model_car)
48
+
49
+
50
+ @create.command("mcp-server")
51
+ @click.argument("project_name")
52
+ @click.option(
53
+ "--target-dir",
54
+ "-t",
55
+ default=None,
56
+ help="Target directory for the project (default: current directory)",
57
+ )
58
+ @click.option(
59
+ "--no-git",
60
+ is_flag=True,
61
+ default=False,
62
+ help="Skip git repository initialization",
63
+ )
64
+ @click.option(
65
+ "--github",
66
+ "use_github",
67
+ is_flag=True,
68
+ default=False,
69
+ help="Create GitHub repository and push code",
70
+ )
71
+ @click.option(
72
+ "--local",
73
+ "use_local",
74
+ is_flag=True,
75
+ default=False,
76
+ help="Create local project only (skip GitHub)",
77
+ )
78
+ @click.option(
79
+ "--yes",
80
+ "-y",
81
+ is_flag=True,
82
+ default=False,
83
+ help="Non-interactive mode (use defaults, skip prompts)",
84
+ )
85
+ @click.option(
86
+ "--private",
87
+ is_flag=True,
88
+ default=False,
89
+ help="Make GitHub repository private (default: public)",
90
+ )
91
+ @click.option(
92
+ "--org",
93
+ default=None,
94
+ help="GitHub organization to create repository in",
95
+ )
96
+ @click.option(
97
+ "--description",
98
+ "-d",
99
+ "repo_description",
100
+ default=None,
101
+ help="GitHub repository description",
102
+ )
103
+ @click.option(
104
+ "--remote-only",
105
+ is_flag=True,
106
+ default=False,
107
+ help="Create GitHub repo only, don't clone locally",
108
+ )
109
+ def mcp_server(
110
+ project_name: str,
111
+ target_dir: str | None,
112
+ no_git: bool,
113
+ use_github: bool,
114
+ use_local: bool,
115
+ yes: bool,
116
+ private: bool,
117
+ org: str | None,
118
+ repo_description: str | None,
119
+ remote_only: bool,
120
+ ):
121
+ """
122
+ Create a new MCP server project from template.
123
+
124
+ PROJECT_NAME must start with a lowercase letter and contain only
125
+ lowercase letters, numbers, hyphens, and underscores.
126
+
127
+ By default, if GitHub CLI (gh) is installed and authenticated, prompts
128
+ to create a GitHub repository. Use --local to skip this, or --github
129
+ to require it. Use --yes for non-interactive mode (agents/CI).
130
+
131
+ Examples:
132
+
133
+ fips-agents create mcp-server my-mcp-server
134
+
135
+ fips-agents create mcp-server my-mcp-server --github --private
136
+
137
+ fips-agents create mcp-server my-mcp-server --local
138
+
139
+ fips-agents create mcp-server my-mcp-server --yes # Non-interactive
140
+ """
141
+ try:
142
+ # Step 1: Validate options
143
+ if use_github and use_local:
144
+ console.print("[red]✗[/red] Cannot use --github and --local together")
145
+ sys.exit(1)
146
+
147
+ if remote_only and use_local:
148
+ console.print("[red]✗[/red] Cannot use --remote-only with --local")
149
+ sys.exit(1)
150
+
151
+ # Step 2: Validate project name
152
+ console.print("\n[bold cyan]Creating MCP Server Project[/bold cyan]\n")
153
+
154
+ is_valid, error_msg = validate_project_name(project_name)
155
+ if not is_valid:
156
+ console.print(f"[red]✗[/red] Invalid project name: {error_msg}")
157
+ sys.exit(1)
158
+
159
+ console.print(f"[green]✓[/green] Project name '{project_name}' is valid")
160
+
161
+ # Step 3: Determine mode (GitHub or local)
162
+ create_github = _determine_github_mode(use_github, use_local, yes)
163
+
164
+ # Step 4: Check prerequisites
165
+ if not is_git_installed():
166
+ console.print(
167
+ "[yellow]⚠[/yellow] Git is not installed. This is required for cloning templates."
168
+ )
169
+ console.print("[yellow]Hint:[/yellow] Install git from https://git-scm.com/downloads")
170
+ sys.exit(1)
171
+
172
+ if create_github:
173
+ ready, error_msg = check_gh_prerequisites()
174
+ if not ready:
175
+ console.print(f"[red]✗[/red] {error_msg}")
176
+ sys.exit(1)
177
+
178
+ # Step 5: Resolve and validate target directory (skip for remote-only)
179
+ target_path = None
180
+ if not remote_only:
181
+ target_path = resolve_target_path(project_name, target_dir)
182
+
183
+ is_valid, error_msg = validate_target_directory(target_path, allow_existing=False)
184
+ if not is_valid:
185
+ console.print(f"[red]✗[/red] {error_msg}")
186
+ console.print(
187
+ "\n[yellow]Hint:[/yellow] Choose a different name or remove the existing "
188
+ "directory"
189
+ )
190
+ sys.exit(1)
191
+
192
+ console.print(f"[green]✓[/green] Target directory: {target_path}")
193
+
194
+ # Step 6: Create GitHub repo first (if GitHub mode)
195
+ github_repo = None
196
+ github_url = None
197
+ if create_github:
198
+ success, github_url, error_msg = create_github_repo(
199
+ name=project_name,
200
+ private=private,
201
+ org=org,
202
+ description=repo_description,
203
+ )
204
+ if not success:
205
+ console.print(f"[red]✗[/red] {error_msg}")
206
+ sys.exit(1)
207
+
208
+ # Construct repo identifier
209
+ owner = org if org else get_github_username()
210
+ github_repo = f"{owner}/{project_name}"
211
+
212
+ # Step 7: Handle remote-only mode
213
+ if remote_only:
214
+ _show_remote_only_success(project_name, github_url, github_repo)
215
+ return
216
+
217
+ # Step 8: Clone template repository
218
+ template_commit = None
219
+ with Progress(
220
+ SpinnerColumn(),
221
+ TextColumn("[progress.description]{task.description}"),
222
+ console=console,
223
+ ) as progress:
224
+ progress.add_task(description="Cloning template repository...", total=None)
225
+ try:
226
+ template_commit = clone_template(MCP_SERVER_TEMPLATE_URL, target_path)
227
+ except Exception as e:
228
+ console.print("\n[red]✗[/red] Failed to clone template repository")
229
+ console.print(f"[red]Error:[/red] {e}")
230
+ console.print(
231
+ f"\n[yellow]Hint:[/yellow] Check your internet connection and verify "
232
+ f"the template URL is accessible:\n{MCP_SERVER_TEMPLATE_URL}"
233
+ )
234
+ sys.exit(1)
235
+
236
+ # Step 9: Customize project
237
+ with Progress(
238
+ SpinnerColumn(),
239
+ TextColumn("[progress.description]{task.description}"),
240
+ console=console,
241
+ ) as progress:
242
+ progress.add_task(description="Customizing project...", total=None)
243
+ try:
244
+ update_project_name(target_path, project_name)
245
+ cleanup_template_files(target_path)
246
+ if template_commit:
247
+ write_template_info(
248
+ target_path,
249
+ project_name,
250
+ MCP_SERVER_TEMPLATE_URL,
251
+ template_commit,
252
+ github_repo=github_repo,
253
+ github_url=github_url,
254
+ )
255
+ except Exception as e:
256
+ console.print("\n[red]✗[/red] Failed to customize project")
257
+ console.print(f"[red]Error:[/red] {e}")
258
+ sys.exit(1)
259
+
260
+ # Step 10: Initialize git repository
261
+ if not no_git:
262
+ with Progress(
263
+ SpinnerColumn(),
264
+ TextColumn("[progress.description]{task.description}"),
265
+ console=console,
266
+ ) as progress:
267
+ progress.add_task(description="Initializing git repository...", total=None)
268
+ try:
269
+ init_repository(target_path, initial_commit=True)
270
+ except Exception as e:
271
+ console.print("\n[yellow]⚠[/yellow] Failed to initialize git repository")
272
+ console.print(f"[yellow]Warning:[/yellow] {e}")
273
+ console.print(
274
+ "[yellow]You can initialize git manually later with:[/yellow] git init"
275
+ )
276
+
277
+ # Step 11: Push to GitHub (if GitHub mode)
278
+ if create_github and not no_git:
279
+ try:
280
+ add_remote(target_path, "origin", github_url)
281
+ push_success = push_to_remote(target_path, "origin", "main")
282
+ if not push_success:
283
+ console.print(
284
+ "\n[yellow]⚠[/yellow] Failed to push to GitHub. "
285
+ "You can push manually with: git push -u origin main"
286
+ )
287
+ except Exception as e:
288
+ console.print(f"\n[yellow]⚠[/yellow] Failed to set up GitHub remote: {e}")
289
+ console.print("[yellow]You can add the remote manually with:[/yellow]")
290
+ console.print(f" git remote add origin {github_url}")
291
+ console.print(" git push -u origin main")
292
+
293
+ # Step 12: Success message
294
+ _show_success_message(
295
+ project_name=project_name,
296
+ target_path=target_path,
297
+ github_url=github_url,
298
+ github_repo=github_repo,
299
+ )
300
+
301
+ except KeyboardInterrupt:
302
+ console.print("\n[yellow]⚠[/yellow] Operation cancelled by user")
303
+ sys.exit(130)
304
+ except Exception as e:
305
+ console.print(f"\n[red]✗[/red] Unexpected error: {e}")
306
+ sys.exit(1)
307
+
308
+
309
+ def _determine_github_mode(use_github: bool, use_local: bool, yes: bool) -> bool:
310
+ """
311
+ Determine whether to create a GitHub repository.
312
+
313
+ Args:
314
+ use_github: --github flag was set
315
+ use_local: --local flag was set
316
+ yes: --yes flag was set (non-interactive mode)
317
+
318
+ Returns:
319
+ bool: True if GitHub repository should be created
320
+ """
321
+ # Explicit flags take precedence
322
+ if use_local:
323
+ console.print("[dim]Mode: Local only (--local)[/dim]")
324
+ return False
325
+
326
+ if use_github:
327
+ console.print("[dim]Mode: GitHub (--github)[/dim]")
328
+ return True
329
+
330
+ # Check if gh is available
331
+ if not is_gh_installed():
332
+ console.print("[dim]Mode: Local only (GitHub CLI not installed)[/dim]")
333
+ return False
334
+
335
+ if not is_gh_authenticated():
336
+ console.print("[dim]Mode: Local only (GitHub CLI not authenticated)[/dim]")
337
+ return False
338
+
339
+ # gh is available - decide based on interactive mode
340
+ if yes:
341
+ # Non-interactive: default to GitHub
342
+ console.print("[dim]Mode: GitHub (--yes with gh available)[/dim]")
343
+ return True
344
+
345
+ # Interactive: prompt user
346
+ console.print("[cyan]GitHub CLI detected and authenticated.[/cyan]")
347
+ return click.confirm("Create GitHub repository?", default=True)
348
+
349
+
350
+ def _show_success_message(
351
+ project_name: str,
352
+ target_path,
353
+ github_url: str | None,
354
+ github_repo: str | None,
355
+ ) -> None:
356
+ """Display success message with next steps."""
357
+ module_name = to_module_name(project_name)
358
+
359
+ # Build project details section
360
+ details = f""" • Name: {project_name}
361
+ • Module: {module_name}
362
+ • Location: {target_path}"""
363
+
364
+ if github_url:
365
+ details += f"\n • GitHub: {github_url}"
366
+
367
+ # Build next steps based on mode
368
+ if github_url:
369
+ next_steps = f"""
370
+ 1. Navigate to your project:
371
+ [dim]cd {target_path.name}[/dim]
372
+
373
+ 2. Create and activate a virtual environment:
374
+ [dim]python -m venv venv[/dim]
375
+ [dim]source venv/bin/activate[/dim] # On Windows: venv\\Scripts\\activate
376
+
377
+ 3. Install the project in editable mode:
378
+ [dim]pip install -e .[dev][/dim]
379
+
380
+ 4. Start developing your MCP server!
381
+ [dim]Your code is already pushed to GitHub[/dim]
382
+
383
+ 5. Run tests:
384
+ [dim]pytest[/dim]"""
385
+ else:
386
+ next_steps = f"""
387
+ 1. Navigate to your project:
388
+ [dim]cd {target_path.name}[/dim]
389
+
390
+ 2. Create and activate a virtual environment:
391
+ [dim]python -m venv venv[/dim]
392
+ [dim]source venv/bin/activate[/dim] # On Windows: venv\\Scripts\\activate
393
+
394
+ 3. Install the project in editable mode:
395
+ [dim]pip install -e .[dev][/dim]
396
+
397
+ 4. Start developing your MCP server!
398
+ [dim]Edit src/ files to add your functionality[/dim]
399
+
400
+ 5. Run tests:
401
+ [dim]pytest[/dim]"""
402
+
403
+ success_message = f"""
404
+ [bold green]✓ Successfully created MCP server project![/bold green]
405
+
406
+ [bold cyan]Project Details:[/bold cyan]
407
+ {details}
408
+
409
+ [bold cyan]Next Steps:[/bold cyan]
410
+ {next_steps}
411
+
412
+ [bold cyan]Documentation:[/bold cyan]
413
+ • Check the README.md in your project for detailed instructions
414
+ • MCP Protocol docs: https://modelcontextprotocol.io/
415
+ """
416
+
417
+ console.print(Panel(success_message, border_style="green", padding=(1, 2)))
418
+
419
+
420
+ def _show_remote_only_success(
421
+ project_name: str,
422
+ github_url: str,
423
+ github_repo: str,
424
+ ) -> None:
425
+ """Display success message for remote-only mode."""
426
+ success_message = f"""
427
+ [bold green]✓ Successfully created GitHub repository![/bold green]
428
+
429
+ [bold cyan]Repository Details:[/bold cyan]
430
+ • Name: {project_name}
431
+ • GitHub: {github_url}
432
+
433
+ [bold cyan]Next Steps:[/bold cyan]
434
+
435
+ 1. Clone the repository:
436
+ [dim]git clone {github_url}[/dim]
437
+ [dim]cd {project_name}[/dim]
438
+
439
+ 2. The repository contains the MCP server template.
440
+ Customize it for your project.
441
+
442
+ [bold cyan]Note:[/bold cyan]
443
+ The repository contains the raw template.
444
+ You may want to customize project names and paths.
445
+ """
446
+
447
+ console.print(Panel(success_message, border_style="green", padding=(1, 2)))
@@ -119,6 +119,21 @@ def docs(dry_run: bool):
119
119
  _patch_category("docs", dry_run)
120
120
 
121
121
 
122
+ @patch.command("build")
123
+ @click.option(
124
+ "--dry-run",
125
+ is_flag=True,
126
+ help="Show what would be updated without making changes",
127
+ )
128
+ def build(dry_run: bool):
129
+ """
130
+ Update build and deployment files (Makefile, Containerfile, etc).
131
+
132
+ Shows diffs and asks for confirmation before applying changes.
133
+ """
134
+ _patch_category("build", dry_run)
135
+
136
+
122
137
  @patch.command("all")
123
138
  @click.option(
124
139
  "--dry-run",
@@ -106,3 +106,63 @@ def is_git_installed() -> bool:
106
106
  return True
107
107
  except (git.GitCommandNotFound, git.GitCommandError):
108
108
  return False
109
+
110
+
111
+ def add_remote(project_path: Path, name: str, url: str) -> None:
112
+ """
113
+ Add a remote to an existing git repository.
114
+
115
+ Args:
116
+ project_path: Path to the project directory
117
+ name: Name of the remote (e.g., "origin")
118
+ url: URL of the remote repository
119
+
120
+ Raises:
121
+ git.GitCommandError: If the remote operation fails
122
+ """
123
+ try:
124
+ repo = git.Repo(str(project_path))
125
+ repo.create_remote(name, url)
126
+ console.print(f"[green]✓[/green] Added remote '{name}': {url}")
127
+ except git.GitCommandError as e:
128
+ console.print(f"[red]✗[/red] Failed to add remote: {e}")
129
+ raise
130
+
131
+
132
+ def push_to_remote(
133
+ project_path: Path,
134
+ remote: str = "origin",
135
+ branch: str = "main",
136
+ set_upstream: bool = True,
137
+ ) -> bool:
138
+ """
139
+ Push the current branch to a remote repository.
140
+
141
+ Args:
142
+ project_path: Path to the project directory
143
+ remote: Name of the remote (default: "origin")
144
+ branch: Name of the branch to push (default: "main")
145
+ set_upstream: Whether to set the upstream tracking branch (default: True)
146
+
147
+ Returns:
148
+ bool: True if push was successful, False otherwise
149
+ """
150
+ try:
151
+ repo = git.Repo(str(project_path))
152
+ remote_obj = repo.remote(remote)
153
+
154
+ console.print(f"[cyan]Pushing to {remote}/{branch}...[/cyan]")
155
+
156
+ if set_upstream:
157
+ remote_obj.push(branch, set_upstream=True)
158
+ else:
159
+ remote_obj.push(branch)
160
+
161
+ console.print(f"[green]✓[/green] Pushed to {remote}/{branch}")
162
+ return True
163
+ except git.GitCommandError as e:
164
+ console.print(f"[red]✗[/red] Failed to push: {e}")
165
+ return False
166
+ except Exception as e:
167
+ console.print(f"[red]✗[/red] Unexpected error during push: {e}")
168
+ return False