@masonator/coolify-mcp 2.6.1 → 2.6.4
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.
|
@@ -802,6 +802,86 @@ describe('CoolifyClient', () => {
|
|
|
802
802
|
expect(result).toEqual({ uuid: 'new-app-uuid' });
|
|
803
803
|
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/applications/private-deploy-key', expect.objectContaining({ method: 'POST' }));
|
|
804
804
|
});
|
|
805
|
+
it('should map fqdn to domains in createApplicationPublic', async () => {
|
|
806
|
+
mockFetch.mockResolvedValueOnce(mockResponse({ uuid: 'new-app-uuid' }));
|
|
807
|
+
await client.createApplicationPublic({
|
|
808
|
+
project_uuid: 'proj-uuid',
|
|
809
|
+
server_uuid: 'server-uuid',
|
|
810
|
+
git_repository: 'https://github.com/user/repo',
|
|
811
|
+
git_branch: 'main',
|
|
812
|
+
build_pack: 'nixpacks',
|
|
813
|
+
ports_exposes: '3000',
|
|
814
|
+
fqdn: 'https://app.example.com',
|
|
815
|
+
});
|
|
816
|
+
const callBody = JSON.parse(mockFetch.mock.calls[0][1]?.body);
|
|
817
|
+
expect(callBody.domains).toBe('https://app.example.com');
|
|
818
|
+
expect(callBody.fqdn).toBeUndefined();
|
|
819
|
+
});
|
|
820
|
+
it('should map fqdn to domains in createApplicationPrivateGH', async () => {
|
|
821
|
+
mockFetch.mockResolvedValueOnce(mockResponse({ uuid: 'new-app-uuid' }));
|
|
822
|
+
await client.createApplicationPrivateGH({
|
|
823
|
+
project_uuid: 'proj-uuid',
|
|
824
|
+
server_uuid: 'server-uuid',
|
|
825
|
+
github_app_uuid: 'gh-app-uuid',
|
|
826
|
+
git_repository: 'user/repo',
|
|
827
|
+
git_branch: 'main',
|
|
828
|
+
build_pack: 'nixpacks',
|
|
829
|
+
ports_exposes: '3000',
|
|
830
|
+
fqdn: 'https://app.example.com',
|
|
831
|
+
});
|
|
832
|
+
const callBody = JSON.parse(mockFetch.mock.calls[0][1]?.body);
|
|
833
|
+
expect(callBody.domains).toBe('https://app.example.com');
|
|
834
|
+
expect(callBody.fqdn).toBeUndefined();
|
|
835
|
+
});
|
|
836
|
+
it('should map fqdn to domains in createApplicationPrivateKey', async () => {
|
|
837
|
+
mockFetch.mockResolvedValueOnce(mockResponse({ uuid: 'new-app-uuid' }));
|
|
838
|
+
await client.createApplicationPrivateKey({
|
|
839
|
+
project_uuid: 'proj-uuid',
|
|
840
|
+
server_uuid: 'server-uuid',
|
|
841
|
+
private_key_uuid: 'key-uuid',
|
|
842
|
+
git_repository: 'git@github.com:user/repo.git',
|
|
843
|
+
git_branch: 'main',
|
|
844
|
+
build_pack: 'nixpacks',
|
|
845
|
+
ports_exposes: '22',
|
|
846
|
+
fqdn: 'https://app.example.com',
|
|
847
|
+
});
|
|
848
|
+
const callBody = JSON.parse(mockFetch.mock.calls[0][1]?.body);
|
|
849
|
+
expect(callBody.domains).toBe('https://app.example.com');
|
|
850
|
+
expect(callBody.fqdn).toBeUndefined();
|
|
851
|
+
});
|
|
852
|
+
it('should map fqdn to domains in updateApplication', async () => {
|
|
853
|
+
mockFetch.mockResolvedValueOnce(mockResponse(mockApplication));
|
|
854
|
+
await client.updateApplication('app-uuid', { fqdn: 'https://new.example.com' });
|
|
855
|
+
const callBody = JSON.parse(mockFetch.mock.calls[0][1]?.body);
|
|
856
|
+
expect(callBody.domains).toBe('https://new.example.com');
|
|
857
|
+
expect(callBody.fqdn).toBeUndefined();
|
|
858
|
+
});
|
|
859
|
+
it('should handle fqdn and docker_compose_raw together in updateApplication', async () => {
|
|
860
|
+
mockFetch.mockResolvedValueOnce(mockResponse(mockApplication));
|
|
861
|
+
const compose = 'version: "3"\nservices:\n app:\n image: nginx';
|
|
862
|
+
await client.updateApplication('app-uuid', {
|
|
863
|
+
fqdn: 'https://combo.example.com',
|
|
864
|
+
docker_compose_raw: compose,
|
|
865
|
+
});
|
|
866
|
+
const callBody = JSON.parse(mockFetch.mock.calls[0][1]?.body);
|
|
867
|
+
expect(callBody.domains).toBe('https://combo.example.com');
|
|
868
|
+
expect(callBody.fqdn).toBeUndefined();
|
|
869
|
+
expect(callBody.docker_compose_raw).toBe(Buffer.from(compose).toString('base64'));
|
|
870
|
+
});
|
|
871
|
+
it('should not modify request body when fqdn is not provided', async () => {
|
|
872
|
+
mockFetch.mockResolvedValueOnce(mockResponse({ uuid: 'new-app-uuid' }));
|
|
873
|
+
await client.createApplicationPublic({
|
|
874
|
+
project_uuid: 'proj-uuid',
|
|
875
|
+
server_uuid: 'server-uuid',
|
|
876
|
+
git_repository: 'https://github.com/user/repo',
|
|
877
|
+
git_branch: 'main',
|
|
878
|
+
build_pack: 'nixpacks',
|
|
879
|
+
ports_exposes: '3000',
|
|
880
|
+
});
|
|
881
|
+
const callBody = JSON.parse(mockFetch.mock.calls[0][1]?.body);
|
|
882
|
+
expect(callBody.fqdn).toBeUndefined();
|
|
883
|
+
expect(callBody.domains).toBeUndefined();
|
|
884
|
+
});
|
|
805
885
|
it('should create application from dockerfile', async () => {
|
|
806
886
|
mockFetch.mockResolvedValueOnce(mockResponse({ uuid: 'new-app-uuid' }));
|
|
807
887
|
const result = await client.createApplicationDockerfile({
|
|
@@ -1381,7 +1461,7 @@ describe('CoolifyClient', () => {
|
|
|
1381
1461
|
mockFetch.mockResolvedValueOnce(mockResponse([mockDeployment]));
|
|
1382
1462
|
const result = await client.listApplicationDeployments('app-uuid');
|
|
1383
1463
|
expect(result).toEqual([mockDeployment]);
|
|
1384
|
-
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/applications/app-uuid
|
|
1464
|
+
expect(mockFetch).toHaveBeenCalledWith('http://localhost:3000/api/v1/deployments/applications/app-uuid', expect.any(Object));
|
|
1385
1465
|
});
|
|
1386
1466
|
});
|
|
1387
1467
|
// =========================================================================
|
|
@@ -28,6 +28,18 @@ function toBase64(value) {
|
|
|
28
28
|
}
|
|
29
29
|
return Buffer.from(value, 'utf-8').toString('base64');
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Map 'fqdn' to 'domains' for Coolify API compatibility.
|
|
33
|
+
* Coolify API uses 'domains' field for setting application domain, not 'fqdn'.
|
|
34
|
+
* This provides backward compatibility for callers using 'fqdn'.
|
|
35
|
+
*/
|
|
36
|
+
function mapFqdnToDomains(data) {
|
|
37
|
+
const { fqdn, ...rest } = data;
|
|
38
|
+
if (fqdn === undefined) {
|
|
39
|
+
return rest;
|
|
40
|
+
}
|
|
41
|
+
return { ...rest, domains: fqdn };
|
|
42
|
+
}
|
|
31
43
|
// =============================================================================
|
|
32
44
|
// Summary Transformers - reduce full objects to essential fields
|
|
33
45
|
// =============================================================================
|
|
@@ -348,19 +360,19 @@ export class CoolifyClient {
|
|
|
348
360
|
async createApplicationPublic(data) {
|
|
349
361
|
return this.request('/applications/public', {
|
|
350
362
|
method: 'POST',
|
|
351
|
-
body: JSON.stringify(data),
|
|
363
|
+
body: JSON.stringify(mapFqdnToDomains(data)),
|
|
352
364
|
});
|
|
353
365
|
}
|
|
354
366
|
async createApplicationPrivateGH(data) {
|
|
355
367
|
return this.request('/applications/private-github-app', {
|
|
356
368
|
method: 'POST',
|
|
357
|
-
body: JSON.stringify(data),
|
|
369
|
+
body: JSON.stringify(mapFqdnToDomains(data)),
|
|
358
370
|
});
|
|
359
371
|
}
|
|
360
372
|
async createApplicationPrivateKey(data) {
|
|
361
373
|
return this.request('/applications/private-deploy-key', {
|
|
362
374
|
method: 'POST',
|
|
363
|
-
body: JSON.stringify(data),
|
|
375
|
+
body: JSON.stringify(mapFqdnToDomains(data)),
|
|
364
376
|
});
|
|
365
377
|
}
|
|
366
378
|
async createApplicationDockerfile(data) {
|
|
@@ -386,9 +398,10 @@ export class CoolifyClient {
|
|
|
386
398
|
});
|
|
387
399
|
}
|
|
388
400
|
async updateApplication(uuid, data) {
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
401
|
+
const mapped = mapFqdnToDomains(data);
|
|
402
|
+
const payload = { ...mapped };
|
|
403
|
+
if (mapped.docker_compose_raw) {
|
|
404
|
+
payload.docker_compose_raw = toBase64(mapped.docker_compose_raw);
|
|
392
405
|
}
|
|
393
406
|
return this.request(`/applications/${uuid}`, {
|
|
394
407
|
method: 'PATCH',
|
|
@@ -659,7 +672,7 @@ export class CoolifyClient {
|
|
|
659
672
|
return this.request(`/deploy?${param}=${encodeURIComponent(tagOrUuid)}&force=${force}`, { method: 'GET' });
|
|
660
673
|
}
|
|
661
674
|
async listApplicationDeployments(appUuid) {
|
|
662
|
-
return this.request(`/applications/${appUuid}
|
|
675
|
+
return this.request(`/deployments/applications/${appUuid}`);
|
|
663
676
|
}
|
|
664
677
|
// ===========================================================================
|
|
665
678
|
// Team endpoints
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@masonator/coolify-mcp",
|
|
3
3
|
"scope": "@masonator",
|
|
4
|
-
"version": "2.6.
|
|
4
|
+
"version": "2.6.4",
|
|
5
5
|
"description": "MCP server implementation for Coolify",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"url": "https://github.com/StuMason/coolify-mcp.git"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
49
49
|
"zod": "^4.3.5"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"jest": "^29.7.0",
|
|
62
62
|
"jest-junit": "^16.0.0",
|
|
63
63
|
"lint-staged": "^16.2.7",
|
|
64
|
-
"markdownlint-cli2": "^0.
|
|
64
|
+
"markdownlint-cli2": "^0.21.0",
|
|
65
65
|
"prettier": "^3.5.3",
|
|
66
66
|
"shx": "^0.4.0",
|
|
67
67
|
"ts-jest": "^29.2.6",
|