mcp-project-creator
Creates a new MCP server package in this monorepo. Uses Python FastMCP 3.0 in a Docker container, deployed to AWS Lambda via CDK and GitHub Actions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Creates a new MCP server package in this monorepo. Uses Python FastMCP 3.0 in a Docker container, deployed to AWS Lambda via CDK and GitHub Actions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | mcp-project-creator |
| description | Creates a new MCP server package in this monorepo. Uses Python FastMCP 3.0 in a Docker container, deployed to AWS Lambda via CDK and GitHub Actions. |
Creates a new MCP server using FastMCP 3.0, Docker, and AWS Lambda.
See CLAUDE.md at the repo root for project context.
packages/{name}/ from references/mcp-server.mdinfrastructure/bin/infrastructure.ts per references/infrastructure.md.github/workflows/deploy.yml per references/shared-env-vars.mdThe per-server steps below assume shared scaffolding already exists. On the first server in a freshly cloned/templated repo, verify (and create if missing):
infrastructure/lib/: shared-stack.ts, mcp-docker-construct.ts, mcp-docker-stack.ts. The skill and the deploy workflow reference these by name but they are easy to miss in a fresh clone. If cd infrastructure && npx cdk synth fails with "Cannot find module", recreate them from references/cdk-constructs.md.bin/infrastructure.ts wires up SharedStack (McpShared-{stage}) — not the default InfrastructureStack scaffold. See references/infrastructure.md.package-lock.json exists and is committed. The CI/deploy workflows run npm ci at the repo root and use actions/setup-node with cache: npm; both fail immediately without a root lockfile. Generate with npm install --package-lock-only at the repo root.AWS_DEPLOY_ROLE_ARN secret are configured for the account you actually deploy to. See references/config-files.md. This is the most common first-deploy failure.A quick local sanity check before relying on CI: npm ci && npm run build --workspace=infrastructure && (cd infrastructure && npx cdk synth).
Confirm each item before declaring the task done:
packages/{name}/ created with app.py, pyproject.toml, .python-version, uv.lock, Dockerfile, .env, README.mdinfrastructure/bin/infrastructure.ts updated with a new McpDockerStack (including the imageTag prop).github/workflows/deploy.ymlsecretsmanager:GetSecretValue added to the stackinfrastructure.ts): referenced the existing constant rather than re-declaring itAsk for the MCP server name in kebab-case (e.g., weather, pdf-tools, github-issues).
Validate:
packages/{name}/_ (reserved for shared internal packages)mkdir -p packages/{name}
Create from references/mcp-server.md:
app.py — FastMCP 3.0 server with create_mcp_server(), lambda_handler(), and a local __main__ entry. Calls load_dotenv() so .env values are picked up automatically when running locally.pyproject.toml — Project metadata + dependencies (fastmcp>=3.0, mangum, uvicorn, python-dotenv, plus any server deps). [tool.uv] package = false marks it as an app..python-version — Pins to 3.12 so uv auto-uses (and auto-installs) the right interpreter.uv.lock — Generated by uv lock (or first uv sync); commit it for reproducible builds.Dockerfile — Multi-stage Lambda container that uses uv to install deps into ${LAMBDA_TASK_ROOT}..env — Placeholder values for local dev (gitignored repo-wide).Create from references/readme-template.md:
README.md — features, tools table, use cases, quick startWhy include use cases in the README? They help AI assistants understand when to use each tool, document expected behavior for ambiguous queries, and double as integration test scenarios.
Edit infrastructure/bin/infrastructure.ts:
new McpDockerStack(app, `McpServer-{name}-${stage}`, {
env,
stage,
serverName: '{name}',
imageTag,
sharedResources: sharedStack.sharedResources,
environment: {
// Lambda env vars (only if the server needs them)
},
});
The imageTag constant (defined at the top of infrastructure.ts) reads process.env.IMAGE_TAG — the deploy workflow sets it to the git SHA so CloudFormation always replaces the Lambda image. Always pass imageTag.
For env vars, IAM permissions, and custom stacks, see references/infrastructure.md.
If the server reads no environment variables, skip this step.
The deploy workflow's "Deploy server stack" step runs cdk deploy. Any process.env.X your CDK code reads must be in its env: block:
- name: Deploy server stack
env:
STAGE: ${{ inputs.environment || 'dev' }}
IMAGE_TAG: ${{ github.sha }}
# {name} env vars:
{NAME}_API_BASE_URL: ${{ vars.{NAME}_API_BASE_URL }}
{NAME}_API_KEY: ${{ secrets.{NAME}_API_KEY }}
{NAME}_ (uppercase, underscores) — prevents collisions as the repo growsvars. for non-sensitive values, secrets. for sensitive onesNote: The deploy workflow auto-detects changed packages — you do not need to update a
workflow_dispatch.optionsdropdown.
Local dev runs directly via uv — no Docker required. app.py calls load_dotenv() on startup, so any values in packages/{name}/.env are picked up automatically.
cd packages/{name}
# Fill in .env with real values for local testing
uv sync # installs deps from uv.lock (creates .venv, downloads Python 3.12 if needed)
PORT=8000 uv run python app.py # uv run auto-activates the project's .venv
# Server: http://localhost:8000
# MCP endpoint: POST http://localhost:8000/mcp
Prerequisite: uv installed (curl -LsSf https://astral.sh/uv/install.sh | sh). uv handles the Python 3.12 install for you via .python-version, so contributors do not need to install python3.12 separately.
Adding a dependency: cd packages/{name} && uv add <package> — this updates both pyproject.toml and uv.lock atomically. Commit both files.
Note: The .env file is gitignored repo-wide (via the root .gitignore's .env entry). Never commit it.
Push to main. GitHub Actions:
packages/{name}/McpServer-{name}-{stage} via CDKThe first deploy creates the ECR repo and Lambda together. Subsequent deploys swap the image based on IMAGE_TAG.
Gotchas:
paths: filter only watches packages/**, infrastructure/**, and deploy.yml. Changes confined to the repo root (e.g. a new root package-lock.json) do not auto-trigger it — use gh workflow run deploy.yml -f server=all -f environment=dev to dispatch manually.curl returns 403. To verify the live endpoint, SigV4-sign a POST {FunctionUrl}mcp request — see references/cdk-constructs.md. The stack outputs FunctionUrl and FunctionName.The McpDockerConstruct sets:
| Setting | Default | Override via |
|---|---|---|
| Runtime | Python 3.12 (Lambda container) | Dockerfile base image |
| Architecture | X86_64 | construct prop |
| Memory | 512 MB | memorySize prop |
| Timeout | 30 s | timeout prop |
| Auth | AWS_IAM | construct prop |
| Log retention | 14 days | construct prop |
Server-specific vars: {SERVER_NAME}_{VAR} (uppercase, underscores).
Examples for weather:
WEATHER_API_BASE_URLWEATHER_API_KEYShared vars (e.g., a common auth provider used by every server) are declared once at the top of infrastructure.ts and reused — they don't carry a server prefix. See references/shared-env-vars.md.
SharedStack, McpDockerStack, McpDockerConstruct) + live-endpoint test