code-engine-mcp-server 1.0.4 → 1.0.6
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.
- package/README.md +277 -38
- package/build/index.js +56 -19
- package/build/index.js.map +1 -1
- package/docs/CONTRIBUTING.md +92 -26
- package/docs/MCP_INSPECTOR_TROUBLESHOOTING.md +232 -0
- package/docs/SETUP_INSTRUCTIONS.md +77 -174
- package/docs/images/inspector-1-setup.png +0 -0
- package/docs/images/inspector-2-connected.png +0 -0
- package/docs/images/inspector-3-tools-list.png +0 -0
- package/docs/images/inspector-4-tool-selected.png +0 -0
- package/docs/images/inspector-5-tool-result.png +0 -0
- package/docs/images/inspector-localhost-1-setup.png +0 -0
- package/docs/images/inspector-localhost-2-connected.png +0 -0
- package/docs/images/inspector-localhost-3-result.png +0 -0
- package/docs/images/inspector-localhost-3-tool-selected.png +0 -0
- package/docs/images/inspector-localhost-4-result-detail.png +0 -0
- package/docs/images/inspector-localhost-4-result.png +0 -0
- package/package.json +7 -2
- package/docs/API_CALL_SCENARIOS.md +0 -594
- package/docs/CODE_ENGINE_API_REFERENCE.md +0 -764
package/README.md
CHANGED
|
@@ -5,32 +5,40 @@
|
|
|
5
5
|
Model Context Protocol (MCP) server for IBM Code Engine and Docker/Podman integration.
|
|
6
6
|
It enables AI assistants to build, run, push, and deploy containerized workloads with a single MCP server.
|
|
7
7
|
|
|
8
|
-
[](
|
|
9
|
-
[](
|
|
8
|
+
[](https://github.com/markusvankempen/code-engine-mcp-server)
|
|
9
|
+
[](https://cloud.ibm.com/codeengine/overview)
|
|
10
10
|
[](#prerequisites)
|
|
11
11
|
[](./LICENSE)
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
13
|
+
## How It Works
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
flowchart TD
|
|
17
|
+
A([AI Assistant\nCopilot / Claude / Cline]) -->|MCP JSON-RPC| B[Code Engine MCP Server]
|
|
18
|
+
|
|
19
|
+
B --> C{Tool Category}
|
|
20
|
+
|
|
21
|
+
C -->|Container Tools| D[Docker / Podman]
|
|
22
|
+
C -->|Registry Tools| E[IBM Container Registry\nus.icr.io]
|
|
23
|
+
C -->|Code Engine Tools| F[IBM Code Engine\nREST API]
|
|
24
|
+
C -->|Procedures| G[Multi-step Workflows]
|
|
25
|
+
|
|
26
|
+
D -->|build / push / validate| E
|
|
27
|
+
E -->|image reference| F
|
|
28
|
+
|
|
29
|
+
G -->|proc_build_push_deploy| D
|
|
30
|
+
G -->|proc_build_run_and_deploy| F
|
|
31
|
+
|
|
32
|
+
F --> H[(Projects\nApps\nBuilds\nJobs\nSecrets\nDomains)]
|
|
33
|
+
|
|
34
|
+
H -->|ready| I([Live App\nhttps://app.region.codeengine.appdomain.cloud])
|
|
35
|
+
|
|
36
|
+
style A fill:#1261FE,color:#fff
|
|
37
|
+
style B fill:#0f3460,color:#fff
|
|
38
|
+
style G fill:#7b2d8b,color:#fff
|
|
39
|
+
style I fill:#198038,color:#fff
|
|
40
|
+
```
|
|
41
|
+
|
|
34
42
|
|
|
35
43
|
## ✨ What You Get
|
|
36
44
|
|
|
@@ -55,7 +63,29 @@ node build/index.js
|
|
|
55
63
|
|
|
56
64
|
Then configure your MCP client using one of the examples in the Configuration section below.
|
|
57
65
|
|
|
58
|
-
##
|
|
66
|
+
## 🤖 The Agentic Experience (No Docker/Code Engine Lingo Needed)
|
|
67
|
+
|
|
68
|
+
The true power of this MCP server is that **you don't need to know Docker or Code Engine commands**. You can simply state your goal, and the LLM will discover the environment, run the pipeline, and fix issues autonomously.
|
|
69
|
+
|
|
70
|
+
Here is an example interaction from a real session:
|
|
71
|
+
|
|
72
|
+
**User:**
|
|
73
|
+
> "I have an app in the `developer-splash` folder. Deploy it to my Code Engine project."
|
|
74
|
+
|
|
75
|
+
**Assistant's Autonomous Thought Process:**
|
|
76
|
+
1. *Discovery:* "Let me check what projects and namespaces exist... Found project `markus-app-v2-toronto` and namespace `mvk-code-engine`."
|
|
77
|
+
2. *Prerequisites:* "No pull secret in this project yet. I'll get the API key from the `.env` file and create the secret `icr-pull-secret`."
|
|
78
|
+
3. *Execution:* "Now I'll run the full pipeline: build → push → deploy → wait."
|
|
79
|
+
4. *Validation:* "It's deployed but stuck at 'deploying'. Let me check the logs... The container is running but the readiness probe is failing."
|
|
80
|
+
5. *Self-Correction:* "Ah, the `sed` pattern in the Dockerfile didn't match nginx alpine's default config format for port 80. I'll fix the Dockerfile with a regex-safe `sed` and rebuild."
|
|
81
|
+
6. *Completion:* "App is live! 🎉 Status: ready."
|
|
82
|
+
|
|
83
|
+
**Assistant Response to User:**
|
|
84
|
+
> "Your app is deployed and live at: `https://developer-splash.29m5mrru3s3n.ca-tor.codeengine.appdomain.cloud`. I had to fix a minor port configuration issue in your Dockerfile, but it is successfully running now!"
|
|
85
|
+
|
|
86
|
+
With this MCP server, the AI acts as an expert DevOps engineer pairing with you.
|
|
87
|
+
|
|
88
|
+
## Deploy Your First App
|
|
59
89
|
|
|
60
90
|
This walks through deploying the included [Star Wars splash page example](./examples/starwars-splash/) — a static nginx container — entirely through the MCP server.
|
|
61
91
|
|
|
@@ -301,14 +331,216 @@ push it, then deploy it to Code Engine project <project-id> with pull secret icr
|
|
|
301
331
|
Tell me the public URL and confirm the instance is running.
|
|
302
332
|
```
|
|
303
333
|
|
|
304
|
-
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 🌐 Host Any MCP Server on Code Engine
|
|
337
|
+
|
|
338
|
+
You can use **this** MCP server to deploy **another** MCP server to Code Engine — no CLI, no Dockerfile, no YAML. The key ingredient is [`supergateway`](https://github.com/supercorp-ai/supergateway): a tiny bridge that wraps any STDIO-based MCP server as an HTTP + SSE endpoint, making it accessible to any remote client.
|
|
339
|
+
|
|
340
|
+
> Credit: [Jeremias Werner & Enrico Regge — IBM Cloud Code Engine](https://community.ibm.com/community/user/blogs/jeremias-werner/2025/04/30/code-engine-mcp-server)
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
Your AI Assistant
|
|
344
|
+
│ MCP JSON-RPC (STDIO, local)
|
|
345
|
+
▼
|
|
346
|
+
code-engine-mcp-server ──► ce_create_application
|
|
347
|
+
│
|
|
348
|
+
▼
|
|
349
|
+
Code Engine App
|
|
350
|
+
image: docker.io/supercorp/supergateway
|
|
351
|
+
args: --stdio "npx -y <any-mcp-server>"
|
|
352
|
+
--outputTransport sse
|
|
353
|
+
│ HTTPS + SSE (public URL)
|
|
354
|
+
▼
|
|
355
|
+
Any remote MCP client
|
|
356
|
+
(Claude Desktop, Cursor, VS Code, …)
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Any STDIO MCP server becomes a remotely accessible, auto-scaling cloud service — with no custom infrastructure.
|
|
360
|
+
|
|
361
|
+
This example deploys [`@tokenizin/mcp-npx-fetch`](https://www.npmjs.com/package/@tokenizin/mcp-npx-fetch), an MCP server that lets an AI assistant fetch content from public URLs.
|
|
362
|
+
|
|
363
|
+
The example files live in [examples/mcp-server-supergateway/](./examples/mcp-server-supergateway/).
|
|
364
|
+
|
|
365
|
+
### Step 1 — Deploy the hosted MCP server
|
|
366
|
+
|
|
367
|
+
Ask your assistant:
|
|
368
|
+
```
|
|
369
|
+
Deploy a hosted MCP fetch server to my Code Engine project <project-id>.
|
|
370
|
+
Use image docker.io/supercorp/supergateway on port 8000.
|
|
371
|
+
Startup args: --stdio "npx -y @tokenizin/mcp-npx-fetch" --outputTransport sse
|
|
372
|
+
Name it "mcp-fetch-server". No pull secret needed.
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
This calls `ce_create_application`:
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"project_id": "<your-project-id>",
|
|
379
|
+
"name": "mcp-fetch-server",
|
|
380
|
+
"image": "docker.io/supercorp/supergateway",
|
|
381
|
+
"port": 8000,
|
|
382
|
+
"run_args": ["--stdio", "npx -y @tokenizin/mcp-npx-fetch", "--outputTransport", "sse"]
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**MCP response — `ce_create_application`:**
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"name": "mcp-fetch-server",
|
|
390
|
+
"resource_type": "app_v2",
|
|
391
|
+
"status": "deploying",
|
|
392
|
+
"image_reference": "docker.io/supercorp/supergateway",
|
|
393
|
+
"image_port": 8000,
|
|
394
|
+
"scale_min_instances": 0,
|
|
395
|
+
"scale_max_instances": 10,
|
|
396
|
+
"endpoint": "https://mcp-fetch-server.<subdomain>.<region>.codeengine.appdomain.cloud",
|
|
397
|
+
"status_details": {
|
|
398
|
+
"latest_created_revision": "mcp-fetch-server-00001",
|
|
399
|
+
"latest_ready_revision": null
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
> No pull secret is needed — `docker.io/supercorp/supergateway` is a public image. Code Engine scales to zero when idle; you pay only for actual requests.
|
|
405
|
+
|
|
406
|
+
### Step 2 — Wait for the app to be ready
|
|
407
|
+
|
|
408
|
+
Ask your assistant:
|
|
409
|
+
```
|
|
410
|
+
Wait for mcp-fetch-server in project <project-id> to be ready
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
This calls `ce_wait_for_app_ready`:
|
|
414
|
+
```json
|
|
415
|
+
{
|
|
416
|
+
"project_id": "<your-project-id>",
|
|
417
|
+
"app_name": "mcp-fetch-server",
|
|
418
|
+
"timeout_seconds": 120
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**MCP response — `ce_wait_for_app_ready`:**
|
|
423
|
+
```json
|
|
424
|
+
{
|
|
425
|
+
"app_name": "mcp-fetch-server",
|
|
426
|
+
"status": "ready",
|
|
427
|
+
"endpoint": "https://mcp-fetch-server.<subdomain>.<region>.codeengine.appdomain.cloud",
|
|
428
|
+
"elapsed_seconds": 34,
|
|
429
|
+
"poll_history": [
|
|
430
|
+
{ "attempt": 1, "status": "deploying", "elapsed_seconds": 10 },
|
|
431
|
+
{ "attempt": 2, "status": "deploying", "elapsed_seconds": 20 },
|
|
432
|
+
{ "attempt": 3, "status": "ready", "elapsed_seconds": 34 }
|
|
433
|
+
]
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Step 3 — Verify the running instance
|
|
438
|
+
|
|
439
|
+
Ask your assistant:
|
|
440
|
+
```
|
|
441
|
+
List the running instances of mcp-fetch-server in project <project-id>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
This calls `ce_list_app_instances`:
|
|
445
|
+
|
|
446
|
+
**MCP response — `ce_list_app_instances`:**
|
|
447
|
+
```json
|
|
448
|
+
{
|
|
449
|
+
"instances": [
|
|
450
|
+
{
|
|
451
|
+
"name": "mcp-fetch-server-00001-deployment-abc123",
|
|
452
|
+
"revision": "mcp-fetch-server-00001",
|
|
453
|
+
"status": "running",
|
|
454
|
+
"restart_count": 0,
|
|
455
|
+
"started_at": "2026-05-09T12:01:44Z"
|
|
456
|
+
}
|
|
457
|
+
]
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Step 4 — Connect your MCP client
|
|
305
462
|
|
|
463
|
+
Use [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) to bridge the HTTP+SSE endpoint back to STDIO for local clients.
|
|
464
|
+
|
|
465
|
+
**VS Code `mcp.json`:**
|
|
466
|
+
```json
|
|
467
|
+
{
|
|
468
|
+
"servers": {
|
|
469
|
+
"fetch": {
|
|
470
|
+
"command": "npx",
|
|
471
|
+
"args": [
|
|
472
|
+
"mcp-remote",
|
|
473
|
+
"https://mcp-fetch-server.<subdomain>.<region>.codeengine.appdomain.cloud/sse"
|
|
474
|
+
]
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
**Claude Desktop `claude_desktop_config.json`:**
|
|
481
|
+
```json
|
|
482
|
+
{
|
|
483
|
+
"mcpServers": {
|
|
484
|
+
"fetch": {
|
|
485
|
+
"command": "npx",
|
|
486
|
+
"args": [
|
|
487
|
+
"mcp-remote",
|
|
488
|
+
"https://mcp-fetch-server.<subdomain>.<region>.codeengine.appdomain.cloud/sse"
|
|
489
|
+
]
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Step 5 — Test the endpoint
|
|
496
|
+
|
|
497
|
+
Verify the server is live and streaming:
|
|
498
|
+
```bash
|
|
499
|
+
curl -N https://mcp-fetch-server.<subdomain>.<region>.codeengine.appdomain.cloud/sse
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
Or open it in the [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
|
|
503
|
+
```bash
|
|
504
|
+
npx @modelcontextprotocol/inspector
|
|
505
|
+
# Connect via SSE → paste the Code Engine URL
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Once connected, you will see the `fetch` tool listed and can invoke it directly from the inspector.
|
|
509
|
+
|
|
510
|
+
### Full one-shot prompt
|
|
511
|
+
|
|
512
|
+
```
|
|
513
|
+
Deploy a hosted MCP fetch server to my Code Engine project <project-id>.
|
|
514
|
+
Use image docker.io/supercorp/supergateway on port 8000 with no pull secret.
|
|
515
|
+
run_args: --stdio "npx -y @tokenizin/mcp-npx-fetch" --outputTransport sse
|
|
516
|
+
Name it "mcp-fetch-server", wait for it to be ready, and give me the /sse URL
|
|
517
|
+
so I can add it to my mcp.json.
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
See [examples/mcp-server-supergateway/](./examples/mcp-server-supergateway/) for the ready-to-use client config file.
|
|
521
|
+
|
|
522
|
+
### Deploy any other STDIO MCP server
|
|
523
|
+
|
|
524
|
+
The same pattern works for any `npx`-runnable MCP server — just swap the `--stdio` argument:
|
|
525
|
+
|
|
526
|
+
| MCP Server | `--stdio` argument |
|
|
527
|
+
|---|---|
|
|
528
|
+
| Fetch | `npx -y @tokenizin/mcp-npx-fetch` |
|
|
529
|
+
| Filesystem | `npx -y @modelcontextprotocol/server-filesystem /data` |
|
|
530
|
+
| Brave Search | `npx -y @modelcontextprotocol/server-brave-search` |
|
|
531
|
+
| Your own server | `node /app/server.js` |
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## Documentation
|
|
536
|
+
|
|
537
|
+
- [Setup Instructions](./docs/SETUP_INSTRUCTIONS.md)
|
|
538
|
+
- [MCP Inspector Troubleshooting](./docs/MCP_INSPECTOR_TROUBLESHOOTING.md)
|
|
306
539
|
- [Code Engine API Reference](./docs/CODE_ENGINE_API_REFERENCE.md)
|
|
307
540
|
- [API Call Scenarios](./docs/API_CALL_SCENARIOS.md)
|
|
308
|
-
- [Setup Instructions](./docs/SETUP_INSTRUCTIONS.md)
|
|
309
541
|
- [Client README](./docs/CLIENT_README.md)
|
|
310
542
|
- [Cline MCP Config Example](./docs/CLINE_CONFIG_EXAMPLE.json)
|
|
311
|
-
- [VS Code MCP extension](./vscode-extension/README.md)
|
|
543
|
+
- [VS Code MCP extension](./vscode-extension/README.md)
|
|
312
544
|
- [Code of Conduct](./docs/CODE_OF_CONDUCT.md)
|
|
313
545
|
- [Contributing Guide](./docs/CONTRIBUTING.md)
|
|
314
546
|
- [Maintainers](./docs/MAINTAINERS.md)
|
|
@@ -317,20 +549,27 @@ Tell me the public URL and confirm the instance is running.
|
|
|
317
549
|
|
|
318
550
|
```text
|
|
319
551
|
code-engine-mcp-server/
|
|
320
|
-
├── api/
|
|
321
|
-
│ └── code-engine-openapi.yaml # OpenAPI reference used for API coverage
|
|
552
|
+
├── api/ # OpenAPI reference used for API coverage
|
|
322
553
|
├── build/ # Compiled JavaScript output
|
|
323
|
-
├── docs/ # API references
|
|
324
|
-
├──
|
|
554
|
+
├── docs/ # API references, client guides, community files
|
|
555
|
+
│ ├── API_CALL_SCENARIOS.md
|
|
556
|
+
│ ├── CODE_ENGINE_API_REFERENCE.md
|
|
557
|
+
│ ├── MCP_INSPECTOR_TROUBLESHOOTING.md
|
|
558
|
+
│ ├── SETUP_INSTRUCTIONS.md
|
|
559
|
+
│ ├── CODE_OF_CONDUCT.md
|
|
560
|
+
│ ├── CONTRIBUTING.md
|
|
561
|
+
│ └── MAINTAINERS.md
|
|
562
|
+
├── examples/
|
|
563
|
+
│ ├── developer-splash/ # nginx static container example
|
|
564
|
+
│ ├── starwars-splash/ # nginx Star Wars crawl example
|
|
565
|
+
│ └── mcp-server-supergateway/ # Host any MCP server on Code Engine via supergateway
|
|
566
|
+
├── internal/ # Internal release notes
|
|
325
567
|
├── src/ # Main TypeScript source code
|
|
326
568
|
├── CHANGELOG.md # Release history
|
|
327
|
-
├── CODE_OF_CONDUCT.md # Community guidelines
|
|
328
|
-
├── CONTRIBUTING.md # Contribution workflow
|
|
329
569
|
├── LICENSE # Project license
|
|
330
|
-
├── MAINTAINERS.md # Maintainer list
|
|
331
570
|
├── README.md # Project overview and usage
|
|
332
571
|
├── mcp.example.json # Example MCP client configuration
|
|
333
|
-
├── vscode-extension/ # Optional VS Code extension
|
|
572
|
+
├── vscode-extension/ # Optional VS Code extension
|
|
334
573
|
├── package.json # npm package metadata and scripts
|
|
335
574
|
├── server.json # MCP Registry metadata
|
|
336
575
|
└── tsconfig.json # TypeScript configuration
|
|
@@ -468,7 +707,7 @@ Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
468
707
|
}
|
|
469
708
|
```
|
|
470
709
|
|
|
471
|
-
##
|
|
710
|
+
## One-Click Install
|
|
472
711
|
|
|
473
712
|
Use the published package from npm or browse the MCP Registry listing:
|
|
474
713
|
|
|
@@ -579,8 +818,8 @@ Tell me what CNAME value to set in DNS.
|
|
|
579
818
|
|------|-------------|----------------|
|
|
580
819
|
| `ce_list_applications` | List applications in a project | `project_id` |
|
|
581
820
|
| `ce_get_application` | Get application details and public URL | `project_id`, `app_name` |
|
|
582
|
-
| `ce_create_application` | Deploy a new application | `project_id`, `name`, `image`, `image_secret`, `port`, `env_vars` |
|
|
583
|
-
| `ce_update_application` | Update image, scaling, env, pull secret | `project_id`, `app_name`, `image`, `image_secret`, `scale_
|
|
821
|
+
| `ce_create_application` | Deploy a new application | `project_id`, `name`, `image`, `image_secret`, `port`, `env_vars`, `run_args`, `run_commands` |
|
|
822
|
+
| `ce_update_application` | Update image, scaling, env, pull secret, run args | `project_id`, `app_name`, `image`, `image_secret`, `scale_*`, `run_args`, `run_commands` |
|
|
584
823
|
| `ce_delete_application` | Delete an application | `project_id`, `app_name` |
|
|
585
824
|
| `ce_list_app_instances` | List all running instances with status | `project_id`, `app_name` |
|
|
586
825
|
| `ce_get_app_instance` | Get status details for a specific instance | `project_id`, `app_name`, `instance_name` |
|
package/build/index.js
CHANGED
|
@@ -86,7 +86,7 @@ async function resolveProjectId(nameOrId, token) {
|
|
|
86
86
|
// Create MCP server
|
|
87
87
|
const server = new Server({
|
|
88
88
|
name: 'code-engine-mcp-server',
|
|
89
|
-
version: '1.0.
|
|
89
|
+
version: '1.0.6',
|
|
90
90
|
}, {
|
|
91
91
|
capabilities: {
|
|
92
92
|
tools: {},
|
|
@@ -322,6 +322,8 @@ const codeEngineTools = [
|
|
|
322
322
|
scale_cpu_limit: { type: 'string', description: 'CPU limit (e.g. 1, 0.5)' },
|
|
323
323
|
scale_memory_limit: { type: 'string', description: 'Memory limit (e.g. 4G, 2G)' },
|
|
324
324
|
env_vars: { type: 'object', description: 'Key/value environment variables' },
|
|
325
|
+
run_args: { type: 'array', items: { type: 'string' }, description: 'Arguments passed to the container entrypoint (run_arguments). Required for supergateway: ["--stdio", "npx -y <mcp-server>", "--outputTransport", "sse"]' },
|
|
326
|
+
run_commands: { type: 'array', items: { type: 'string' }, description: 'Override the container entrypoint (run_commands). Rarely needed — use run_args for passing flags.' },
|
|
325
327
|
},
|
|
326
328
|
required: ['project_id', 'name', 'image'],
|
|
327
329
|
},
|
|
@@ -340,6 +342,8 @@ const codeEngineTools = [
|
|
|
340
342
|
scale_max_instances: { type: 'number' },
|
|
341
343
|
scale_cpu_limit: { type: 'string' },
|
|
342
344
|
scale_memory_limit: { type: 'string' },
|
|
345
|
+
run_args: { type: 'array', items: { type: 'string' }, description: 'Arguments passed to the container entrypoint (run_arguments)' },
|
|
346
|
+
run_commands: { type: 'array', items: { type: 'string' }, description: 'Override the container entrypoint (run_commands)' },
|
|
343
347
|
},
|
|
344
348
|
required: ['project_id', 'app_name'],
|
|
345
349
|
},
|
|
@@ -383,15 +387,16 @@ const codeEngineTools = [
|
|
|
383
387
|
},
|
|
384
388
|
{
|
|
385
389
|
name: 'ce_get_app_logs',
|
|
386
|
-
description: 'Get logs for a specific Code Engine
|
|
390
|
+
description: 'Get logs for a Code Engine application. Retrieves logs from all running pods (or a specific instance) via the Code Engine Kubernetes API proxy.',
|
|
387
391
|
inputSchema: {
|
|
388
392
|
type: 'object',
|
|
389
393
|
properties: {
|
|
390
|
-
project_id: { type: 'string' },
|
|
391
|
-
app_name: { type: 'string' },
|
|
392
|
-
instance_name: { type: 'string', description: '
|
|
394
|
+
project_id: { type: 'string', description: 'Project ID or name' },
|
|
395
|
+
app_name: { type: 'string', description: 'Application name' },
|
|
396
|
+
instance_name: { type: 'string', description: 'Optional: specific pod/instance name to filter to (e.g. my-app-00001-deployment-abcde). If omitted, logs from all pods are returned.' },
|
|
397
|
+
tail_lines: { type: 'number', description: 'Number of log lines to return per pod (default: 100)' },
|
|
393
398
|
},
|
|
394
|
-
required: ['project_id', 'app_name'
|
|
399
|
+
required: ['project_id', 'app_name'],
|
|
395
400
|
},
|
|
396
401
|
},
|
|
397
402
|
// --- Builds ---
|
|
@@ -1259,6 +1264,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1259
1264
|
type: 'literal', name, value,
|
|
1260
1265
|
}));
|
|
1261
1266
|
}
|
|
1267
|
+
if (args.run_args)
|
|
1268
|
+
body.run_arguments = args.run_args;
|
|
1269
|
+
if (args.run_commands)
|
|
1270
|
+
body.run_commands = args.run_commands;
|
|
1262
1271
|
const response = await axios.post(`${base}/apps`, body, { headers });
|
|
1263
1272
|
return { content: [{ type: 'text', text: JSON.stringify(response.data, null, 2) }] };
|
|
1264
1273
|
}
|
|
@@ -1283,6 +1292,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1283
1292
|
patch.scale_cpu_limit = args.scale_cpu_limit;
|
|
1284
1293
|
if (args.scale_memory_limit)
|
|
1285
1294
|
patch.scale_memory_limit = args.scale_memory_limit;
|
|
1295
|
+
if (args.run_args)
|
|
1296
|
+
patch.run_arguments = args.run_args;
|
|
1297
|
+
if (args.run_commands)
|
|
1298
|
+
patch.run_commands = args.run_commands;
|
|
1286
1299
|
const response = await axios.patch(`${base}/apps/${args.app_name}`, patch, {
|
|
1287
1300
|
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/merge-patch+json', 'If-Match': entityTag },
|
|
1288
1301
|
});
|
|
@@ -1313,22 +1326,46 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1313
1326
|
}
|
|
1314
1327
|
case 'ce_get_app_logs': {
|
|
1315
1328
|
const token = await getIAMToken(getApiKey());
|
|
1316
|
-
const
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1329
|
+
const projectId = await resolveProjectId(args.project_id, token);
|
|
1330
|
+
const region = await getProjectRegion(projectId, token);
|
|
1331
|
+
const ceHeaders = { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' };
|
|
1332
|
+
// Get app details to extract namespace/subdomain from the endpoint URL
|
|
1333
|
+
const appRes = await axios.get(`https://api.${region}.codeengine.cloud.ibm.com/v2/projects/${projectId}/apps/${args.app_name}`, { headers: ceHeaders });
|
|
1334
|
+
// Endpoint pattern: https://{app}.{subdomain}.{region}.codeengine.appdomain.cloud
|
|
1335
|
+
const endpoint = appRes.data.endpoint || '';
|
|
1336
|
+
const subdomainMatch = endpoint.match(/https?:\/\/[^.]+\.([^.]+)\.[^.]+\.codeengine/);
|
|
1337
|
+
if (!subdomainMatch) {
|
|
1338
|
+
return { content: [{ type: 'text', text: JSON.stringify({ error: 'Could not determine project namespace from app endpoint', endpoint }, null, 2) }] };
|
|
1320
1339
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1340
|
+
const namespace = subdomainMatch[1];
|
|
1341
|
+
const proxyBase = `https://proxy.${region}.codeengine.cloud.ibm.com`;
|
|
1342
|
+
const tailLines = args.tail_lines ?? 100;
|
|
1343
|
+
const kubeHeaders = { Authorization: `Bearer ${token}` };
|
|
1344
|
+
// List pods for the app via Kubernetes API proxy
|
|
1345
|
+
const labelSelector = encodeURIComponent(`serving.knative.dev/service=${args.app_name}`);
|
|
1346
|
+
const podsRes = await axios.get(`${proxyBase}/api/v1/namespaces/${namespace}/pods?labelSelector=${labelSelector}`, { headers: kubeHeaders });
|
|
1347
|
+
const pods = podsRes.data.items || [];
|
|
1348
|
+
if (pods.length === 0) {
|
|
1349
|
+
return { content: [{ type: 'text', text: JSON.stringify({ message: `No pods found for app '${args.app_name}'`, namespace, app: args.app_name }, null, 2) }] };
|
|
1350
|
+
}
|
|
1351
|
+
// Filter to a specific instance if requested
|
|
1352
|
+
const targetPods = args.instance_name
|
|
1353
|
+
? pods.filter((p) => p.metadata.name === args.instance_name || p.metadata.name.startsWith(String(args.instance_name)))
|
|
1354
|
+
: pods;
|
|
1355
|
+
// Fetch logs for each pod
|
|
1356
|
+
const results = [];
|
|
1357
|
+
for (const pod of targetPods) {
|
|
1358
|
+
const podName = pod.metadata.name;
|
|
1359
|
+
const podPhase = pod.status?.phase ?? 'Unknown';
|
|
1360
|
+
try {
|
|
1361
|
+
const logRes = await axios.get(`${proxyBase}/api/v1/namespaces/${namespace}/pods/${podName}/log?container=user-container&tailLines=${tailLines}`, { headers: kubeHeaders });
|
|
1362
|
+
results.push({ pod: podName, status: podPhase, logs: logRes.data });
|
|
1363
|
+
}
|
|
1364
|
+
catch (logErr) {
|
|
1365
|
+
results.push({ pod: podName, status: podPhase, error: logErr.response?.data?.message ?? logErr.message });
|
|
1329
1366
|
}
|
|
1330
|
-
throw err;
|
|
1331
1367
|
}
|
|
1368
|
+
return { content: [{ type: 'text', text: JSON.stringify({ app: args.app_name, namespace, region, pods_found: pods.length, results }, null, 2) }] };
|
|
1332
1369
|
}
|
|
1333
1370
|
case 'ce_list_builds': {
|
|
1334
1371
|
const token = await getIAMToken(getApiKey());
|