fix(mcp): save MCP deployments as MCP, not as API deployments

This commit is contained in:
Andras Bacsai committed 2026-11-03 13:56:43 +01:00
1 parent c3a21eceeb
commit b063a41624
13 files changed
+70 -9

No files matched your search

+1
View File
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
### Fixed
- Handle an existing Cloudflare DNS record with a different IP when Coolify adds the DNS record of a new domain automatically. Coolify now replaces the record when it created the record and no other resource uses it. Otherwise it opens the **Configure DNS** dialog, where you can replace the record, and the domain shows the conflict instead of "Not checked"
- Save deployments started through the MCP server as MCP deployments, not as API deployments. The deployment list shows them with the **MCP** source and filter, and the API and MCP deployment data have a new `is_mcp` field
## [v4.6.0] - 2026-11-02
@@ -26,6 +26,7 @@ class Index extends Component
'commit_message',
'is_webhook',
'is_api',
'is_mcp',
'rollback',
'server_id',
'server_name',
@@ -297,6 +298,7 @@ class Index extends Component
WHEN pull_request_id > 0 THEN 'pull-request'
WHEN is_webhook THEN 'webhook'
WHEN rollback THEN 'rollback'
WHEN is_mcp THEN 'mcp'
WHEN is_api THEN 'api'
ELSE 'manual'
END AS source_key
@@ -309,6 +311,7 @@ class Index extends Component
'pull-request' => 'Pull requests',
'webhook' => 'Webhooks',
'api' => 'API',
'mcp' => 'MCP',
'rollback' => 'Rollbacks',
];
+1 -1
View File
@@ -125,7 +125,7 @@ class Control extends Tool
deployment_uuid: $deploymentUuid,
force_rebuild: false,
restart_only: $action === 'restart',
is_api: true,
is_mcp: true,
no_questions_asked: $action === 'start',
);
+1 -1
View File
@@ -74,7 +74,7 @@ class Deploy extends Tool
deployment_uuid: $deploymentUuid,
pull_request_id: $pullRequestId,
force_rebuild: $force,
is_api: true,
is_mcp: true,
no_questions_asked: true,
);
+1
View File
@@ -72,6 +72,7 @@ class GetDeployment extends Tool
'force_rebuild' => $deployment->force_rebuild,
'is_webhook' => $deployment->is_webhook,
'is_api' => $deployment->is_api,
'is_mcp' => $deployment->is_mcp,
'restart_only' => $deployment->restart_only,
'rollback' => $deployment->rollback,
'git_type' => $deployment->git_type,
+1
View File
@@ -120,6 +120,7 @@ class ListDeployments extends Tool
'force_rebuild' => $deployment->force_rebuild,
'is_webhook' => $deployment->is_webhook,
'is_api' => $deployment->is_api,
'is_mcp' => $deployment->is_mcp,
'deployment_url' => $deployment->deployment_url,
'created_at' => $deployment->created_at,
'updated_at' => $deployment->updated_at,
+5 -2
View File
@@ -1378,12 +1378,14 @@ class Application extends BaseModel
'webhook', 'webhooks' => $query->orWhere('is_webhook', true),
'rollback', 'rollbacks' => $query->orWhere('rollback', true),
'api' => $query->orWhere('is_api', true),
'mcp' => $query->orWhere('is_mcp', true),
'manual' => $query->orWhere(function ($sourceQuery) {
$sourceQuery
->where('pull_request_id', '<=', 0)
->where('is_webhook', false)
->where('rollback', false)
->where('is_api', false);
->where('is_api', false)
->where('is_mcp', false);
}),
default => null,
};
@@ -1409,7 +1411,8 @@ class Application extends BaseModel
'webhook' => $sourceQuery->where('pull_request_id', '<=', 0)->where('is_webhook', true),
'rollback' => $sourceQuery->where('pull_request_id', '<=', 0)->where('is_webhook', false)->where('rollback', true),
'api' => $sourceQuery->where('pull_request_id', '<=', 0)->where('is_webhook', false)->where('rollback', false)->where('is_api', true),
'manual' => $sourceQuery->where('pull_request_id', '<=', 0)->where('is_webhook', false)->where('rollback', false)->where('is_api', false),
'mcp' => $sourceQuery->where('pull_request_id', '<=', 0)->where('is_webhook', false)->where('rollback', false)->where('is_mcp', true),
'manual' => $sourceQuery->where('pull_request_id', '<=', 0)->where('is_webhook', false)->where('rollback', false)->where('is_api', false)->where('is_mcp', false),
default => $sourceQuery->where('id', -1),
};
});
+12 -2
View File
@@ -32,6 +32,7 @@ use OpenApi\Attributes as OA;
'status' => ['type' => 'string'],
'is_webhook' => ['type' => 'boolean'],
'is_api' => ['type' => 'boolean'],
'is_mcp' => ['type' => 'boolean'],
'created_at' => ['type' => 'string'],
'updated_at' => ['type' => 'string'],
'logs' => ['type' => 'string'],
@@ -89,7 +90,11 @@ class ApplicationDeploymentQueue extends Model
}
$application = $deployment->application;
$source = $deployment->is_api ? 'api' : 'ui';
$source = match (true) {
(bool) $deployment->is_mcp => 'mcp',
(bool) $deployment->is_api => 'api',
default => 'ui',
};
auditLog("{$source}.application.rollback", [
'team_id' => $application?->team()?->id,
@@ -108,7 +113,11 @@ class ApplicationDeploymentQueue extends Model
}
$application = $deployment->application;
$source = $deployment->is_api ? 'api' : 'ui';
$source = match (true) {
(bool) $deployment->is_mcp => 'mcp',
(bool) $deployment->is_api => 'api',
default => 'ui',
};
auditLog("{$source}.deployment.cancelled", [
'team_id' => $application?->team()?->id,
@@ -145,6 +154,7 @@ class ApplicationDeploymentQueue extends Model
'rollback',
'commit_message',
'is_api',
'is_mcp',
'build_server_id',
'horizon_job_id',
'horizon_job_worker',
+8 -3
View File
@@ -16,7 +16,7 @@ use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Spatie\Url\Url;
function queue_application_deployment(Application $application, string $deployment_uuid, ?int $pull_request_id = 0, ?string $commit = null, bool $force_rebuild = false, bool $is_webhook = false, bool $is_api = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, ?Server $server = null, ?StandaloneDocker $destination = null, bool $only_this_server = false, bool $rollback = false, ?string $docker_registry_image_tag = null, ?string $parent_deployment_uuid = null)
function queue_application_deployment(Application $application, string $deployment_uuid, ?int $pull_request_id = 0, ?string $commit = null, bool $force_rebuild = false, bool $is_webhook = false, bool $is_api = false, bool $restart_only = false, ?string $git_type = null, bool $no_questions_asked = false, ?Server $server = null, ?StandaloneDocker $destination = null, bool $only_this_server = false, bool $rollback = false, ?string $docker_registry_image_tag = null, ?string $parent_deployment_uuid = null, bool $is_mcp = false)
{
$commit = $commit ?: ($application->git_commit_sha ?: 'HEAD');
$commit = validateGitRef($commit, 'deployment commit');
@@ -35,7 +35,11 @@ function queue_application_deployment(Application $application, string $deployme
$destination_id = $destination->id;
}
$admission = DB::transaction(function () use ($application, $application_id, $commit, $deployment_uuid, $deployment_url, $destination_id, $docker_registry_image_tag, $force_rebuild, $git_type, $is_api, $is_webhook, $no_questions_asked, $only_this_server, $parent_deployment_uuid, $pull_request_id, $restart_only, $rollback, $server_id, $server_name) {
// MCP tools also call the REST API controllers through an internal request.
$is_mcp = $is_mcp || request()->attributes->get('mcp_rest_bridge') === true;
$is_api = $is_api && ! $is_mcp;
$admission = DB::transaction(function () use ($application, $application_id, $commit, $deployment_uuid, $deployment_url, $destination_id, $docker_registry_image_tag, $force_rebuild, $git_type, $is_api, $is_mcp, $is_webhook, $no_questions_asked, $only_this_server, $parent_deployment_uuid, $pull_request_id, $restart_only, $rollback, $server_id, $server_name) {
// Lock stable rows because an empty deployment queue has no row to lock.
Application::query()->whereKey($application_id)->lockForUpdate()->firstOrFail();
$serverForQueueCheck = Server::query()->whereKey($server_id)->lockForUpdate()->firstOrFail();
@@ -80,6 +84,7 @@ function queue_application_deployment(Application $application, string $deployme
'force_rebuild' => $force_rebuild,
'is_webhook' => $is_webhook,
'is_api' => $is_api,
'is_mcp' => $is_mcp,
'restart_only' => $restart_only,
'commit' => $commit,
'rollback' => $rollback,
@@ -106,7 +111,7 @@ function queue_application_deployment(Application $application, string $deployme
$deployment = $admission['deployment'];
if (auth()->check() && ! $is_webhook && ! $is_api && ! $rollback) {
if (auth()->check() && ! $is_webhook && ! $is_api && ! $is_mcp && ! $rollback) {
auditLog($restart_only ? 'ui.application.restarted' : 'ui.application.deployed', [
'application_uuid' => $application->uuid,
'application_name' => $application->name,
@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (Schema::hasColumn('application_deployment_queues', 'is_mcp')) {
return;
}
Schema::table('application_deployment_queues', function (Blueprint $table) {
$table->boolean('is_mcp')->default(false);
});
}
public function down(): void
{
if (! Schema::hasColumn('application_deployment_queues', 'is_mcp')) {
return;
}
Schema::table('application_deployment_queues', function (Blueprint $table) {
$table->dropColumn('is_mcp');
});
}
};
+3
View File
@@ -27187,6 +27187,9 @@
"is_api": {
"type": "boolean"
},
"is_mcp": {
"type": "boolean"
},
"created_at": {
"type": "string"
},
+2
View File
@@ -17360,6 +17360,8 @@ components:
type: boolean
is_api:
type: boolean
is_mcp:
type: boolean
created_at:
type: string
updated_at:
@@ -237,6 +237,7 @@
(bool) data_get($deployment, 'is_webhook') => 'Webhook',
$pullRequestId > 0 => 'Pull request #' . $pullRequestId,
(bool) data_get($deployment, 'rollback') => 'Rollback',
(bool) data_get($deployment, 'is_mcp') => 'MCP',
(bool) data_get($deployment, 'is_api') => 'API',
default => 'Manual',
};
@@ -244,6 +245,7 @@
$pullRequestId > 0 => 'pull-request',
(bool) data_get($deployment, 'is_webhook') => 'webhook',
(bool) data_get($deployment, 'rollback') => 'rollback',
(bool) data_get($deployment, 'is_mcp') => 'mcp',
(bool) data_get($deployment, 'is_api') => 'api',
default => 'manual',
};