mcp-creator-python 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,122 @@
1
+ """Scaffold a complete MCP server project."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ from mcp_creator.services import codegen, file_writer
9
+
10
+
11
+ def scaffold_server(
12
+ package_name: str,
13
+ description: str,
14
+ tools: str,
15
+ output_dir: str = ".",
16
+ env_vars: str | None = None,
17
+ paid: bool = False,
18
+ paid_tools: str | None = None,
19
+ hosting: str = "local",
20
+ ) -> str:
21
+ """Scaffold a complete, runnable MCP server project.
22
+
23
+ Args:
24
+ package_name: PyPI package name (e.g. "my-weather-mcp").
25
+ description: One-line description of the server.
26
+ tools: JSON string — list of tool defs:
27
+ [{"name": "get_weather", "description": "...",
28
+ "parameters": [{"name": "city", "type": "string",
29
+ "required": true, "description": "..."}],
30
+ "returns": "Weather data as JSON"}]
31
+ output_dir: Parent directory where the project folder is created.
32
+ env_vars: Optional JSON string — list of env var defs:
33
+ [{"name": "API_KEY", "description": "...", "required": true}]
34
+ paid: If true, add license key gating via mcp-marketplace-license SDK.
35
+ paid_tools: Optional JSON string — list of tool names to gate behind license.
36
+ If omitted and paid=true, all tools are gated.
37
+ hosting: "local" (default, stdio) or "remote" (SSE/HTTP for hosted model).
38
+
39
+ Returns:
40
+ JSON string with created files and next steps.
41
+ """
42
+ tool_defs = json.loads(tools)
43
+ env_var_defs = json.loads(env_vars) if env_vars else None
44
+ paid_tool_list = json.loads(paid_tools) if paid_tools else None
45
+ module_name = codegen._to_module_name(package_name)
46
+
47
+ # Build file dict: relative_path -> content
48
+ files: dict[str, str] = {}
49
+
50
+ # Root files
51
+ files["pyproject.toml"] = codegen.render_pyproject(package_name, description, paid=paid)
52
+ files[".gitignore"] = codegen.render_gitignore()
53
+ files["README.md"] = codegen.render_readme(
54
+ package_name, description, tool_defs, paid=paid, hosting=hosting,
55
+ )
56
+
57
+ env_content = codegen.render_env_example(env_var_defs, paid=paid, hosting=hosting)
58
+ if env_content:
59
+ files[".env.example"] = env_content
60
+
61
+ if hosting == "remote":
62
+ files["Dockerfile"] = codegen.render_dockerfile(package_name)
63
+
64
+ # Source package
65
+ src = f"src/{module_name}"
66
+ files[f"{src}/__init__.py"] = codegen.render_init(package_name)
67
+ files[f"{src}/server.py"] = codegen.render_server(
68
+ package_name, tool_defs, paid=paid, paid_tools=paid_tool_list, hosting=hosting,
69
+ )
70
+ files[f"{src}/transport.py"] = codegen.render_transport(package_name)
71
+
72
+ # Tools and services
73
+ files[f"{src}/tools/__init__.py"] = ""
74
+ files[f"{src}/services/__init__.py"] = ""
75
+
76
+ for tool in tool_defs:
77
+ tool_name = tool["name"]
78
+ files[f"{src}/tools/{tool_name}.py"] = codegen.render_tool_module(
79
+ package_name, tool
80
+ )
81
+ files[f"{src}/services/{tool_name}_service.py"] = codegen.render_service_module(
82
+ tool
83
+ )
84
+
85
+ # Tests
86
+ files["tests/test_server.py"] = codegen.render_test_server(package_name, tool_defs)
87
+ for tool in tool_defs:
88
+ files[f"tests/test_{tool['name']}.py"] = codegen.render_test_tool(
89
+ package_name, tool
90
+ )
91
+
92
+ # Write to disk
93
+ project_dir = Path(output_dir).resolve() / package_name
94
+ written = file_writer.write_project_files(project_dir, files)
95
+
96
+ result = {
97
+ "success": True,
98
+ "project_dir": str(project_dir),
99
+ "files_created": len(written),
100
+ "file_list": sorted(files.keys()),
101
+ "module_name": module_name,
102
+ "paid": paid,
103
+ "hosting": hosting,
104
+ "next_steps": [
105
+ f"Project scaffolded at {project_dir}",
106
+ f"cd {project_dir} && uv venv .venv && source .venv/bin/activate && uv pip install -e '.[dev]'",
107
+ "Open the services/ folder and replace the TODO stubs with your real logic.",
108
+ "Run 'pytest -v' to verify everything works.",
109
+ "When ready, use build_package to build and publish_package to publish to PyPI.",
110
+ ],
111
+ }
112
+
113
+ if paid:
114
+ result["next_steps"].append(
115
+ "License gating is enabled. Users need MCP_LICENSE_KEY to use paid tools."
116
+ )
117
+ if hosting == "remote":
118
+ result["next_steps"].append(
119
+ "Remote hosting enabled. Use 'docker build' and 'docker run' to deploy."
120
+ )
121
+
122
+ return json.dumps(result, indent=2)
@@ -0,0 +1,137 @@
1
+ """Initialize git and create a GitHub repo for the MCP server project."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ from mcp_creator.services.subprocess_runner import run_command
9
+
10
+
11
+ def setup_github(
12
+ project_dir: str,
13
+ repo_name: str,
14
+ description: str = "",
15
+ private: bool = False,
16
+ ) -> str:
17
+ """Initialize a git repo, create a GitHub repo, and push the project.
18
+
19
+ Requires the `gh` CLI to be installed and authenticated.
20
+
21
+ Args:
22
+ project_dir: Absolute path to the project root.
23
+ repo_name: GitHub repo name (e.g. "my-weather-mcp").
24
+ description: One-line repo description.
25
+ private: If True, create a private repo. Default is public.
26
+
27
+ Returns:
28
+ JSON string with repo URL and next steps.
29
+ """
30
+ project = Path(project_dir).resolve()
31
+
32
+ if not project.exists():
33
+ return json.dumps({
34
+ "success": False,
35
+ "error": f"Project directory not found: {project}",
36
+ })
37
+
38
+ # 1. Check gh CLI is available
39
+ gh_check = run_command(["gh", "auth", "status"], cwd=project)
40
+ if not gh_check["success"]:
41
+ return json.dumps({
42
+ "success": False,
43
+ "error": "GitHub CLI (gh) is not installed or not authenticated.",
44
+ "next_steps": [
45
+ "Install gh: https://cli.github.com/",
46
+ "Then run: gh auth login",
47
+ ],
48
+ })
49
+
50
+ # 2. git init (if not already a repo)
51
+ git_check = run_command(["git", "rev-parse", "--git-dir"], cwd=project)
52
+ if not git_check["success"]:
53
+ init_result = run_command(["git", "init"], cwd=project)
54
+ if not init_result["success"]:
55
+ return json.dumps({
56
+ "success": False,
57
+ "error": f"git init failed: {init_result['stderr']}",
58
+ })
59
+
60
+ # 3. Stage and commit all files
61
+ run_command(["git", "add", "."], cwd=project)
62
+ commit_result = run_command(
63
+ ["git", "commit", "-m", "Initial commit — scaffolded with mcp-creator"],
64
+ cwd=project,
65
+ )
66
+ # commit may fail if already committed — that's ok
67
+
68
+ # 4. Create GitHub repo
69
+ visibility = "--private" if private else "--public"
70
+ create_args = [
71
+ "gh", "repo", "create", repo_name,
72
+ visibility,
73
+ "--source", str(project),
74
+ "--push",
75
+ ]
76
+ if description:
77
+ create_args.extend(["--description", description])
78
+
79
+ create_result = run_command(create_args, cwd=project, timeout=30)
80
+
81
+ if not create_result["success"]:
82
+ # Maybe repo already exists — try to just add remote and push
83
+ if "already exists" in create_result["stderr"].lower():
84
+ # Get the GitHub username
85
+ whoami = run_command(["gh", "api", "user", "--jq", ".login"], cwd=project)
86
+ username = whoami["stdout"].strip() if whoami["success"] else "OWNER"
87
+ repo_url = f"https://github.com/{username}/{repo_name}"
88
+
89
+ run_command(
90
+ ["git", "remote", "add", "origin", f"{repo_url}.git"],
91
+ cwd=project,
92
+ )
93
+ push_result = run_command(
94
+ ["git", "push", "-u", "origin", "main"],
95
+ cwd=project,
96
+ timeout=30,
97
+ )
98
+ if not push_result["success"]:
99
+ # Try HEAD branch name
100
+ run_command(
101
+ ["git", "push", "-u", "origin", "HEAD"],
102
+ cwd=project,
103
+ timeout=30,
104
+ )
105
+
106
+ return json.dumps({
107
+ "success": True,
108
+ "repo_url": repo_url,
109
+ "note": "Repo already existed — pushed to it.",
110
+ "next_steps": [
111
+ f"Code pushed to {repo_url}",
112
+ "Use generate_launchguide with this URL as the docs_url.",
113
+ ],
114
+ })
115
+
116
+ return json.dumps({
117
+ "success": False,
118
+ "error": f"Failed to create GitHub repo: {create_result['stderr']}",
119
+ "next_steps": [
120
+ "Check that gh is authenticated: gh auth status",
121
+ "Try creating the repo manually: gh repo create",
122
+ ],
123
+ })
124
+
125
+ # 5. Get the repo URL
126
+ whoami = run_command(["gh", "api", "user", "--jq", ".login"], cwd=project)
127
+ username = whoami["stdout"].strip() if whoami["success"] else "OWNER"
128
+ repo_url = f"https://github.com/{username}/{repo_name}"
129
+
130
+ return json.dumps({
131
+ "success": True,
132
+ "repo_url": repo_url,
133
+ "next_steps": [
134
+ f"GitHub repo created: {repo_url}",
135
+ "Use generate_launchguide with this URL as the docs_url for marketplace submission.",
136
+ ],
137
+ })
@@ -0,0 +1,11 @@
1
+ """Transport helpers for mcp-creator."""
2
+
3
+
4
+ def run_stdio(mcp_app):
5
+ """Run the MCP server over stdio (default for Claude Code / Cursor)."""
6
+ mcp_app.run(transport="stdio")
7
+
8
+
9
+ def run_http(mcp_app, host: str = "0.0.0.0", port: int = 8000):
10
+ """Run the MCP server over HTTP (for remote hosting)."""
11
+ mcp_app.run(transport="sse", host=host, port=port)
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-creator-python
3
+ Version: 1.0.0
4
+ Summary: Create, build, and publish Python MCP servers to PyPI — conversationally
5
+ License: MIT
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: mcp[cli]>=1.0.0
8
+ Provides-Extra: dev
9
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
10
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
11
+ Description-Content-Type: text/markdown
12
+
13
+ # mcp-creator
14
+
15
+ Create, build, and publish Python MCP servers to PyPI — conversationally.
16
+
17
+ Install `mcp-creator`, add it to your AI assistant, and it walks you through the entire process: naming your package, scaffolding a complete project, building, and publishing to PyPI.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pip install mcp-creator
23
+ ```
24
+
25
+ ## Setup
26
+
27
+ Add to Claude Code (`~/.claude/settings.json`):
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "mcp-creator": {
33
+ "command": "mcp-creator",
34
+ "args": []
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ Or for Cursor (`.cursor/mcp.json`):
41
+
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "mcp-creator": {
46
+ "command": "mcp-creator",
47
+ "args": []
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ ## Tools
54
+
55
+ | Tool | What it does |
56
+ |------|-------------|
57
+ | `get_creator_profile` | Load your persistent profile — setup status, project history. Called first every session. |
58
+ | `update_creator_profile` | Save setup state, usernames, and project history across sessions |
59
+ | `check_setup` | Detect what's installed (uv, git, gh, PyPI token) — only walks through missing steps |
60
+ | `check_pypi_name` | Check if a package name is available on PyPI |
61
+ | `scaffold_server` | Create a complete MCP server project from a name + description + tool definitions |
62
+ | `add_tool` | Add a new tool to an existing scaffolded project |
63
+ | `build_package` | Run `uv build` on the project |
64
+ | `publish_package` | Run `uv publish` to PyPI |
65
+ | `setup_github` | Initialize git, create a GitHub repo, and push the code |
66
+ | `generate_launchguide` | Create LAUNCHGUIDE.md for marketplace submission |
67
+
68
+ ## How It Works
69
+
70
+ 1. **Tell your AI what you want to build**: "I want an MCP server that checks the weather"
71
+ 2. **It checks the name**: calls `check_pypi_name` to verify availability on PyPI
72
+ 3. **It scaffolds the project**: calls `scaffold_server` with your tool definitions — generates a complete, runnable project
73
+ 4. **You fill in the logic**: replace the TODO stubs in `services/` with your real API calls
74
+ 5. **Build & publish**: `build_package` → `publish_package` → live on PyPI
75
+ 6. **Push to GitHub**: `setup_github` creates a repo and pushes your code
76
+ 7. **Submit to marketplace**: `generate_launchguide` creates the submission file with your repo URL
77
+
78
+ ## What Gets Generated
79
+
80
+ For a project named `my-weather-mcp` with a `get_weather` tool:
81
+
82
+ ```
83
+ my-weather-mcp/
84
+ ├── pyproject.toml ← hatchling build, mcp[cli] dep, CLI entry point
85
+ ├── README.md ← install instructions + MCP config JSON
86
+ ├── .gitignore
87
+ ├── src/my_weather_mcp/
88
+ │ ├── __init__.py
89
+ │ ├── server.py ← FastMCP + @mcp.tool() for each tool
90
+ │ ├── transport.py
91
+ │ ├── tools/
92
+ │ │ ├── __init__.py
93
+ │ │ └── get_weather.py
94
+ │ └── services/
95
+ │ ├── __init__.py
96
+ │ └── get_weather_service.py ← TODO: your logic here
97
+ └── tests/
98
+ ├── test_server.py
99
+ └── test_get_weather.py
100
+ ```
101
+
102
+ The generated server runs immediately — stub services return placeholder data so you can test before implementing real logic.
103
+
104
+ ## Requirements
105
+
106
+ - Python 3.11+
107
+ - [uv](https://docs.astral.sh/uv/) (for building and publishing)
108
+
109
+ ## Development
110
+
111
+ ```bash
112
+ git clone https://github.com/gmoneyn/mcp-creator.git
113
+ cd mcp-creator
114
+ uv venv .venv && source .venv/bin/activate
115
+ uv pip install -e ".[dev]"
116
+ pytest -v
117
+ ```
@@ -0,0 +1,22 @@
1
+ mcp_creator/__init__.py,sha256=CDnhWvgG3-f_b63ojeUkXnc0M65xloLEqFiAAYFM7WE,77
2
+ mcp_creator/server.py,sha256=-QFwJ9P8tIU4kuJYytB2GMhjqvmphP-KykjC2WYwE4c,6633
3
+ mcp_creator/transport.py,sha256=Rt6TCg9f9RLuE3qc_r-rbBw3emeGOl5xtc4pky1hQw4,360
4
+ mcp_creator/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ mcp_creator/services/codegen.py,sha256=m0ia1gjyYAqy6336RXztlJXFLEvwrZdV17rXk6-KoOo,18005
6
+ mcp_creator/services/file_writer.py,sha256=sfSGgxOy7BqnmBUV7HPpcBpvRHa2uxGtN6CWubm0Xyc,1129
7
+ mcp_creator/services/pypi_client.py,sha256=PhLplSDZIqdL1zjas2tNF4JIjL2jQsIk0nfytsZmpnY,1828
8
+ mcp_creator/services/subprocess_runner.py,sha256=8KLmiipvDvEFu8oZZqthXFMFaY2A8BG-tP-sa1Uwan0,1447
9
+ mcp_creator/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ mcp_creator/tools/add_tool.py,sha256=Sm2c8Wk93fCu9rFDNnPhLHWg0P1BxSNnjssz0hnVWhI,3139
11
+ mcp_creator/tools/build_package.py,sha256=OKXUiRM5-Ja7J8OEi5wMDmK1Z83zDH3VuhDlrvfbTI8,1531
12
+ mcp_creator/tools/check_pypi_name.py,sha256=0KfMaESyyXdXKtcE-DOm0_a6fiyhmSBONEM0hfXTJn4,1155
13
+ mcp_creator/tools/check_setup.py,sha256=HFBR454bDwTBN0Buan_-_ottQSUYFgjBpWAotvEPz4s,3439
14
+ mcp_creator/tools/creator_profile.py,sha256=LimuPZAzqCmDIgzvYt-Vc06BEwxiFyctVEM0BlNIvF4,3692
15
+ mcp_creator/tools/generate_launchguide.py,sha256=B8m3js0eNgMt4IhQ2tIuxjkN6PokTKMNITDTmJcDUTE,2391
16
+ mcp_creator/tools/publish_package.py,sha256=HBu96cz3D1gswqHczNytZnAX1pAXwyi5Tqv9O4fbmdk,2629
17
+ mcp_creator/tools/scaffold_server.py,sha256=wNrJPriHwkSlxLR9AhstCd05zs5Bs3fK7X-hFI8YNyc,4557
18
+ mcp_creator/tools/setup_github.py,sha256=nEWhJ8980JuncX80H7jemJ40dJwACVoO5kIuRYWWMe0,4697
19
+ mcp_creator_python-1.0.0.dist-info/METADATA,sha256=M3ylLvuMcjck2RqhKBW7j6bJZFcmNvFYhbOIFhDsJZg,3730
20
+ mcp_creator_python-1.0.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
21
+ mcp_creator_python-1.0.0.dist-info/entry_points.txt,sha256=yeXobTrjeJR7EAMxUxV-F7Jps88ER2qwd2M_d8SRlHo,63
22
+ mcp_creator_python-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ mcp-creator-python = mcp_creator.server:main