Code Engine MCP Server

Model Context Protocol (MCP) server for IBM Code Engine and Docker/Podman integration.
It enables AI assistants to build, run, push, and deploy containerized workloads with a single MCP server.

๐ Table of Contents
โจ What You Get
- Container workflow tools for Docker or Podman
- IBM Container Registry (ICR) tools โ list namespaces, list images, delete images
- IBM Code Engine project and application management tools
- MCP-ready setup for GitHub Copilot, Cline, Claude Desktop, and the optional VS Code extension in
vscode-extension/
- A simple local development and troubleshooting workflow
๐ Quick Start
npm install
npm run build
node build/index.js
Then configure your MCP client using one of the examples in the Configuration section below.
๏ฟฝ Deploy Your First App
This walks through deploying the included Star Wars splash page example โ a static nginx container โ entirely through the MCP server.
Apple Silicon users: always build with --platform linux/amd64. Code Engine runs amd64 only.
Step 1 โ Build and push the image
cd examples/starwars-splash
podman build --platform linux/amd64 -t us.icr.io/<your-namespace>/starwars-splash:v1.0.0 .
podman push us.icr.io/<your-namespace>/starwars-splash:v1.0.0
Or ask your assistant:
Build examples/starwars-splash as us.icr.io/my-namespace/starwars-splash:v1.0.0 for linux/amd64 and push it
MCP response โ build_container_image:
{
"success": true,
"command": "podman build --platform linux/amd64 -t us.icr.io/my-namespace/starwars-splash:v1.0.0 ...",
"build_output": "STEP 1/5: FROM nginx:alpine\nSTEP 2/5: COPY index.html /usr/share/nginx/html/index.html\nSTEP 3/5: RUN sed -i 's/listen 80;/listen 8080;/g' /etc/nginx/conf.d/default.conf\nSTEP 4/5: EXPOSE 8080\nSTEP 5/5: CMD [\"nginx\", \"-g\", \"daemon off;\"]\nSuccessfully tagged us.icr.io/my-namespace/starwars-splash:v1.0.0"
}
Note: Container runtimes (Podman/Docker) write build progress to stderr. The build_output field combines stdout and stderr so you see the full build log.
MCP response โ push_container_image:
{
"success": true,
"command": "podman push us.icr.io/my-namespace/starwars-splash:v1.0.0",
"output": "Getting image source signatures\nCopying blobs...\nWriting manifest to image destination"
}
Step 2 โ Create a registry pull secret
Ask your assistant (once per project):
Create a registry secret called icr-pull-secret in project <project-id> for us.icr.io using my IBM Cloud API key
Or use the ce_create_secret tool directly:
{
"project_id": "<your-project-id>",
"name": "icr-pull-secret",
"format": "registry",
"data": {
"username": "iamapikey",
"password": "<your-ibm-cloud-api-key>",
"server": "us.icr.io",
"email": "user@example.com"
}
}
MCP response โ ce_create_secret:
{
"name": "icr-pull-secret",
"format": "registry",
"resource_type": "secret_registry_v2",
"created_at": "2026-05-08T22:10:00Z",
"project_id": "<your-project-id>"
}
Step 3 โ Deploy the application
Ask your assistant:
Deploy us.icr.io/my-namespace/starwars-splash:v1.0.0 to Code Engine project <project-id>
as app "starwars-splash" using pull secret icr-pull-secret, min 1 instance
Or use the ce_create_application tool:
{
"project_id": "<your-project-id>",
"name": "starwars-splash",
"image": "us.icr.io/<your-namespace>/starwars-splash:v1.0.0",
"image_secret": "icr-pull-secret",
"scale_min_instances": 1,
"scale_max_instances": 3
}
MCP response โ ce_create_application:
{
"name": "starwars-splash",
"resource_type": "app_v2",
"status": "deploying",
"image_reference": "us.icr.io/my-namespace/starwars-splash:v1.0.0",
"image_secret": "icr-pull-secret",
"image_port": 8080,
"scale_min_instances": 1,
"scale_max_instances": 3,
"scale_cpu_limit": "1",
"scale_memory_limit": "4G",
"endpoint": "https://starwars-splash.<subdomain>.us-south.codeengine.appdomain.cloud",
"status_details": {
"latest_created_revision": "starwars-splash-00001",
"latest_ready_revision": null
}
}
Step 4 โ Check deployment status
Get details for the starwars-splash app in project <project-id>
This calls ce_get_application and returns the public URL once the app reaches ready status.
List the running instances of starwars-splash in project <project-id>
This calls ce_list_app_instances (or ce_get_app_instance for a specific instance) and shows:
- Instance name and revision
- Container status (
running / pending / failed)
- Restart count
- Started-at timestamp
- CPU and memory allocation
MCP response โ ce_get_application (once ready):
{
"name": "starwars-splash",
"status": "ready",
"image_reference": "us.icr.io/my-namespace/starwars-splash:v1.0.0",
"image_port": 8080,
"scale_min_instances": 1,
"scale_max_instances": 3,
"scale_cpu_limit": "0.5",
"scale_memory_limit": "1G",
"region": "us-south",
"endpoint": "https://starwars-splash.<subdomain>.us-south.codeengine.appdomain.cloud",
"status_details": {
"latest_created_revision": "starwars-splash-00001",
"latest_ready_revision": "starwars-splash-00001"
}
}
Step 5 โ Map a custom domain (optional)
To serve the app at your own domain (e.g. myapp.example.com) you need a TLS certificate. The IBM Code Engine REST API always requires a real certificate โ IBM's Console "Platform managed" option is not available via the API.
5a โ Get a Let's Encrypt certificate (certbot)
brew install certbot
mkdir -p ~/certbot/{config,work,logs}
/opt/homebrew/bin/certbot certonly --manual --preferred-challenges dns \
-d <your-domain> --agree-tos --no-eff-email --email you@example.com \
--config-dir ~/certbot/config --work-dir ~/certbot/work --logs-dir ~/certbot/logs
Certbot will pause and ask you to add a TXT record:
Add TXT record: _acme-challenge.<your-domain> = <challenge-value>
Verify propagation, then press Enter. Certbot writes:
~/certbot/config/live/<your-domain>/fullchain.pem
~/certbot/config/live/<your-domain>/privkey.pem
5b โ Create the TLS secret in Code Engine
Ask your assistant:
Create a TLS secret called starwars-tls in project <project-id>
using cert ~/certbot/config/live/myapp.example.com/fullchain.pem
and key ~/certbot/config/live/myapp.example.com/privkey.pem
This calls ce_create_tls_secret_from_pem โ reads the PEM files from disk and stores them as a Code Engine tls secret.
MCP response โ ce_create_tls_secret_from_pem:
{
"name": "my-tls",
"format": "tls",
"resource_type": "secret_tls_v2",
"created_at": "2026-05-08T22:30:00Z",
"project_id": "<your-project-id>"
}
5c โ Create the domain mapping
Ask your assistant:
Map domain myapp.example.com to app my-app
in project <project-id> using TLS secret my-tls
This calls ce_create_domain_mapping and returns the cname_target.
MCP response โ ce_create_domain_mapping:
{
"name": "myapp.example.com",
"status": "ready",
"cname_target": "custom.<subdomain>.us-south.codeengine.appdomain.cloud",
"component": {
"resource_type": "app_v2",
"name": "my-app"
},
"tls_secret": "my-tls",
"region": "us-south"
}
5d โ Update your CNAME
In your DNS provider, set:
myapp.example.com CNAME custom.<subdomain>.us-south.codeengine.appdomain.cloud
Use the cname_target value returned in 5c (it uses the custom. prefix, not the app name).
Once DNS propagates, https://<your-domain> serves the app with a valid TLS certificate.
Certificate renewal: Let's Encrypt certs expire after 90 days. Re-run certbot to get updated PEM files, then ask Copilot to run ce_renew_tls_secret_from_pem โ it patches the existing secret in-place so your domain mapping continues working without any changes.
Full one-shot prompt
I have a Star Wars splash page in examples/starwars-splash.
Build it for linux/amd64 as us.icr.io/my-namespace/starwars-splash:v1.0.0,
push it, then deploy it to Code Engine project <project-id> with pull secret icr-pull-secret.
Tell me the public URL and confirm the instance is running.
๏ฟฝ๐ Documentation
๐๏ธ Project Structure
code-engine-mcp-server/
โโโ api/
โ โโโ code-engine-openapi.yaml # OpenAPI reference used for API coverage
โโโ build/ # Compiled JavaScript output
โโโ docs/ # API references and setup guides
โโโ internal/ # Internal release/publishing notes
โโโ src/ # Main TypeScript source code
โโโ CHANGELOG.md # Release history
โโโ CODE_OF_CONDUCT.md # Community guidelines
โโโ CONTRIBUTING.md # Contribution workflow
โโโ LICENSE # Project license
โโโ MAINTAINERS.md # Maintainer list
โโโ README.md # Project overview and usage
โโโ mcp.example.json # Example MCP client configuration
โโโ vscode-extension/ # Optional VS Code extension (MCP definition provider)
โโโ package.json # npm package metadata and scripts
โโโ server.json # MCP Registry metadata
โโโ tsconfig.json # TypeScript configuration
๐งฉ Features
Container Runtime Tools (Docker/Podman)
- โ
Detect container runtime (Docker/Podman)
- โ
Build container images (with platform targeting for amd64)
- โ
Push images to registries
- โ
List local images
- โ
Test containers locally
- โ
Get container logs
- โ
Stop and remove containers
- โ
List all containers
- โ
Validate Dockerfile for Code Engine compatibility (
ce_validate_dockerfile) โ checks architecture, port, nginx sed patterns, USER, CMD
IBM Container Registry (ICR)
- โ
List ICR namespaces
- โ
List images with optional namespace filter
- โ
Delete images by tag
IBM Code Engine Tools
- โ
List, create, and delete projects
- โ
Deploy applications with image pull secrets
- โ
Update applications (image, scaling, env)
- โ
List applications and get public URLs
- โ
Get per-instance status (running, restarts, started-at)
- โ
Get application logs per instance
- โ
Build and job management
- โ
Secrets and ConfigMaps
- โ
Custom domain mappings (create, list, get, delete)
- โ
TLS secrets from Let's Encrypt / certbot PEM files (
ce_create_tls_secret_from_pem)
- โ
TLS cert renewal in-place without disrupting domain mappings (
ce_renew_tls_secret_from_pem)
- โ
Update any secret in-place (
ce_update_secret)
- โ
Wait for app deployment or build run to complete (
ce_wait_for_app_ready, ce_wait_for_build_run)
- โ
IAM token info and diagnostics (
iam_get_token_info)
- โ
Create ICR namespaces via REST API (
icr_create_namespace)
Procedures
- โ
proc_build_push_deploy โ full container pipeline in one prompt (build โ push โ deploy โ wait)
- โ
proc_setup_custom_domain โ TLS cert + domain mapping in one step, returns CNAME target
- โ
proc_build_run_and_deploy โ CE source build โ wait โ deploy app โ wait โ return URL
โ๏ธ Configuration
VS Code โ IBM Code Engine MCP extension (optional)
The extension in vscode-extension/ registers this MCP server with VS Code using the MCP server definition provider API (VS Code 1.101+). You do not need a workspace .vscode/mcp.json entry for the default flow: the server is started with npx -y code-engine-mcp-server and your API key from settings.
- Install the extension (from a
.vsix built with npm run package inside vscode-extension/, or from the Marketplace when published).
- Ensure Node.js is installed and
npx is on your PATH.
- Open Settings and search for IBM Code Engine MCP, or edit
settings.json directly:
codeEngineMcp.apiKey โ your IBM Cloud API key (required; until this is set, the extension contributes no MCP server).
codeEngineMcp.region โ IBM Cloud region (optional, default us-south). Passed as IBMCLOUD_REGION to the server.
The extension sets IBMCLOUD_API_KEY and IBMCLOUD_REGION for the spawned process. Use GitHub Copilot and MCP in VS Code as described in the Copilot documentation.
More detail: vscode-extension/README.md.
1) GitHub Copilot (VS Code) โ mcp.json (workspace)
Copy mcp.example.json to .vscode/mcp.json in your workspace root:
cp mcp.example.json ../.vscode/mcp.json
Then edit .vscode/mcp.json and replace the placeholder with your IBM Cloud API key:
{
"servers": {
"code-engine": {
"type": "stdio",
"command": "node",
"args": [
"${workspaceFolder}/code-engine-mcp-server/build/index.js"
],
"env": {
"IBMCLOUD_API_KEY": "your-ibm-cloud-api-key-here"
}
}
}
}
Restart the server: Cmd+Shift+P -> "MCP: Restart Server" -> code-engine.
Security: Add .vscode/mcp.json to your .gitignore to avoid committing your API key.
Get your API key at IBM Cloud IAM โ API keys.
2) Cline (VS Code Extension)
- Open VSCode Settings (Cmd/Ctrl + ,)
- Search for "Cline: MCP Settings"
- Click "Edit in settings.json"
- Add the configuration:
{
"cline.mcpServers": {
"code-engine": {
"command": "node",
"args": ["/absolute/path/to/code-engine-mcp-server/build/index.js"],
"env": {
"IBMCLOUD_API_KEY": "your-api-key-here"
}
}
}
}
3) Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"code-engine": {
"command": "node",
"args": ["/absolute/path/to/code-engine-mcp-server/build/index.js"],
"env": {
"IBMCLOUD_API_KEY": "your-api-key-here"
}
}
}
}
npm and MCP Registry
Use the published package from npm or browse the MCP Registry listing:
๐ฌ Example Prompts
Detect Container Runtime
Ask your assistant:
Can you detect which container runtime I have installed?
Build a Container Image
Ask your assistant:
Build a container image from ./Dockerfile with the name myapp:latest
Test Container Locally
Ask your assistant:
Test the myapp:latest image locally on port 8080
Push to Registry
Ask your assistant:
Push myapp:latest to icr.io/my-namespace/myapp:latest
List Code Engine Projects
Ask your assistant:
List all my Code Engine projects
Complete Workflow
Ask your assistant:
I have a Node.js app in ./my-app with a Dockerfile. Can you:
1. Build it as myapp:v1.0.0
2. Test it locally on port 3000
3. Push it to icr.io/my-namespace/myapp:v1.0.0
4. Deploy it to my Code Engine project "production"
5. Show me the application URL
Custom Domain
Ask your assistant:
Create a TLS secret called my-tls in project <project-id>
using cert ~/certbot/config/live/example.com/fullchain.pem
and key ~/certbot/config/live/example.com/privkey.pem.
Then map domain example.com to app my-app using that secret.
Tell me what CNAME value to set in DNS.
๐ ๏ธ Available Tools
62 tools total: 9 container tools + 4 ICR tools + 45 Code Engine tools + 1 IAM tool + 3 procedures.
Procedures bundle multiple tools into a single call. Use them for common end-to-end workflows.
Container Tools (8)
detect_container_runtime | Detect Docker or Podman | โ |
list_local_images | List local container images | runtime |
list_local_containers | List local containers | runtime, all |
build_container_image | Build a container image | dockerfile_path, image_name, context_path |
push_container_image | Push image to registry | image_name, runtime |
test_container_locally | Run container for local testing | image_name, port_mapping, env_vars |
get_container_logs | Get logs from a running container | container_id, runtime |
stop_local_container | Stop and remove a container | container_id, runtime |
ce_validate_dockerfile | Validate a Dockerfile for Code Engine compatibility (architecture, port, nginx sed patterns, USER, CMD) | dockerfile_path, context_path, expected_port |
IBM Container Registry Tools (4)
icr_list_namespaces | List ICR namespaces in your account | region |
icr_list_images | List images in ICR (optionally filtered by namespace) | namespace, region |
icr_delete_image | Delete an image by full tag | image, region |
icr_create_namespace | Create a new ICR namespace | namespace, region |
Code Engine: Projects (4)
ce_list_projects | List all projects in a region | โ |
ce_get_project | Get project details | project_id |
ce_create_project | Create a new project | name, resource_group_id |
ce_delete_project | Delete a project | project_id |
Code Engine: Applications (9)
ce_list_applications | List applications in a project | project_id |
ce_get_application | Get application details and public URL | project_id, app_name |
ce_create_application | Deploy a new application | project_id, name, image, image_secret, port, env_vars |
ce_update_application | Update image, scaling, env, pull secret | project_id, app_name, image, image_secret, scale_* |
ce_delete_application | Delete an application | project_id, app_name |
ce_list_app_instances | List all running instances with status | project_id, app_name |
ce_get_app_instance | Get status details for a specific instance | project_id, app_name, instance_name |
ce_get_app_logs | Get logs for an app instance | project_id, app_name, instance_name |
ce_wait_for_app_ready | Poll until app status is ready or timeout; returns poll_history | project_id, app_name, timeout_seconds |
Code Engine: Builds (9)
ce_list_builds | List build configurations | project_id |
ce_get_build | Get build configuration details | project_id, build_name |
ce_create_build | Create a build configuration | project_id, name, output_image, output_secret |
ce_delete_build | Delete a build configuration | project_id, build_name |
ce_list_build_runs | List build runs | project_id |
ce_get_build_run | Get build run status | project_id, build_run_name |
ce_create_build_run | Start a build run | project_id, build_name |
ce_delete_build_run | Delete a build run | project_id, build_run_name |
ce_wait_for_build_run | Poll until build run succeeds or fails; returns poll_history | project_id, build_run_name, timeout_seconds |
Code Engine: Jobs (8)
ce_list_jobs | List job definitions | project_id |
ce_get_job | Get job definition details | project_id, job_name |
ce_create_job | Create a job definition | project_id, name, image |
ce_delete_job | Delete a job definition | project_id, job_name |
ce_list_job_runs | List job runs | project_id, job_name (optional) |
ce_get_job_run | Get job run status | project_id, job_run_name |
ce_create_job_run | Submit a job run | project_id, job_name |
ce_delete_job_run | Delete a job run | project_id, job_run_name |
Code Engine: Secrets (7)
ce_list_secrets | List secrets (names + keys only) | project_id |
ce_get_secret | Get secret metadata (no values) | project_id, secret_name |
ce_create_secret | Create a secret | project_id, name, format, data |
ce_update_secret | Update an existing secret in-place (PATCH) | project_id, secret_name, data |
ce_delete_secret | Delete a secret | project_id, secret_name |
ce_create_tls_secret_from_pem | Create a TLS secret from PEM files | project_id, secret_name, cert_pem_path, key_pem_path |
ce_renew_tls_secret_from_pem | Renew an existing TLS secret from updated PEM files | project_id, secret_name, cert_pem_path, key_pem_path |
Code Engine: ConfigMaps (4)
ce_list_config_maps | List configmaps | project_id |
ce_get_config_map | Get configmap details | project_id, config_map_name |
ce_create_config_map | Create a configmap | project_id, name, data |
ce_delete_config_map | Delete a configmap | project_id, config_map_name |
Code Engine: Domain Mappings (4)
ce_list_domain_mappings | List all custom domain mappings | project_id |
ce_get_domain_mapping | Get status and CNAME target for a mapping | project_id, domain_name |
ce_create_domain_mapping | Map a custom domain to an app | project_id, domain_name, app_name, tls_secret |
ce_delete_domain_mapping | Delete a custom domain mapping | project_id, domain_name |
IBM Cloud IAM (1)
iam_get_token_info | Inspect the current IAM token โ account, expiry, validity | โ |
Procedures โ Multi-Step Workflows (3)
proc_build_push_deploy | Build container for linux/amd64 โ push โ create/update CE app โ wait for ready โ return URL + poll_history | context_path, project_id_or_name, app_name, image_secret, icr_namespace, image_tag (default latest), icr_host (default us.icr.io), port, timeout_seconds |
proc_setup_custom_domain | Read PEM files โ create TLS secret โ create domain mapping โ return CNAME target | project_id_or_name, app_name, domain_name, tls_secret_name, cert_pem_path, key_pem_path |
proc_build_run_and_deploy | Start CE build run โ wait for success โ create/update app โ wait for ready โ return URL + build_poll_history + app_poll_history | project_id_or_name, build_name, app_name, image_secret, port, build_timeout_seconds, deploy_timeout_seconds |
๐ Environment Variables
IBMCLOUD_API_KEY: IBM Cloud API key (required for Code Engine operations)
IBMCLOUD_REGION: Default IBM Cloud region (optional, defaults to us-south)
CONTAINER_RUNTIME: Force specific runtime (docker or podman)
DEBUG: Enable debug logging
๐ Prerequisites
- Node.js v18 or higher
- Docker or Podman installed (for container build/push tools)
- IBM Cloud API key (for all Code Engine and ICR operations)
The MCP server communicates directly with the IBM Cloud REST API and ICR API. No IBM Cloud CLI or Code Engine plugin is required.
๐ฉโ๐ป Development
npm run dev
npm run build
node build/index.js
๐งช Troubleshooting
Server Not Connecting
- Verify the path in configuration is absolute
- Check Node.js is in PATH:
node --version
- Verify build output exists:
ls build/index.js
- Test manually:
node build/index.js
Docker/Podman Commands Failing
- Verify installation:
docker --version or podman --version
- Check Docker daemon is running
- Verify permissions (add user to docker group if needed)
Code Engine Commands Failing
- Verify your API key is set: check
IBMCLOUD_API_KEY in your MCP client config
- Confirm the region is correct (default
us-south); set IBMCLOUD_REGION if needed
- Verify the project ID is valid: use
ce_list_projects to find it
- Check for expired tokens โ the server re-fetches IAM tokens automatically; if errors persist, regenerate your API key at IBM Cloud IAM โ API keys
๐ก๏ธ Security
- Never commit API keys to version control
- Use environment variables for sensitive data
- Consider using IBM Cloud IAM for authentication
- Restrict MCP server permissions as needed
๐ License
MIT (see LICENSE)
๐ค Contributing
Contributions are welcome! Please open an issue or submit a pull request (see Contributing Guide).
๐ค Author
Markus van Kempen
Email: markus.van.kempen@gmail.com | mvankempen@ca.ibm.com
Website: markusvankempen.github.io
Research | Floor 7 1/2
๐ Support
For issues and questions: