otoinstall-mcp-server 1.0.0

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 ADDED
@@ -0,0 +1,278 @@
1
+ # 🚀 @otoinstall/mcp-server
2
+
3
+ **Deploy projects from any AI tool with a single command.**
4
+
5
+ Works with **Claude Desktop**, **Cursor**, **Windsurf**, **Cline**, **Continue**, **Zed**, **Roo Code**, **Amazon Q**, and any MCP-compatible AI assistant.
6
+
7
+ ---
8
+
9
+ ## Quick Start
10
+
11
+ ### 1. Get Your API Key
12
+
13
+ Sign up at [otoinstall.com](https://otoinstall.com) → Dashboard → **API Keys** → Create Key
14
+
15
+ ### 2. Configure Your AI Tool
16
+
17
+ Choose your tool below and add the configuration:
18
+
19
+ ---
20
+
21
+ ## 🤖 Claude Desktop
22
+
23
+ Edit `claude_desktop_config.json`:
24
+
25
+ **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
26
+ **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "otoinstall": {
32
+ "command": "npx",
33
+ "args": ["-y", "@otoinstall/mcp-server"],
34
+ "env": {
35
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here",
36
+ "OTOINSTALL_BASE_URL": "https://otoinstall.com"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ---
44
+
45
+ ## 🖱️ Cursor
46
+
47
+ Settings → **MCP Servers** → Add:
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "otoinstall": {
53
+ "command": "npx",
54
+ "args": ["-y", "@otoinstall/mcp-server"],
55
+ "env": {
56
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here"
57
+ }
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ Or via `.cursor/mcp.json` in your project root.
64
+
65
+ ---
66
+
67
+ ## 🏄 Windsurf
68
+
69
+ Settings → **MCP** → Add server:
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "otoinstall": {
75
+ "command": "npx",
76
+ "args": ["-y", "@otoinstall/mcp-server"],
77
+ "env": {
78
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 🔌 Cline (VS Code Extension)
88
+
89
+ Cline settings → **MCP Servers** → Add:
90
+
91
+ ```json
92
+ {
93
+ "mcpServers": {
94
+ "otoinstall": {
95
+ "command": "npx",
96
+ "args": ["-y", "@otoinstall/mcp-server"],
97
+ "env": {
98
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here"
99
+ }
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ ---
106
+
107
+ ## ➡️ Continue (VS Code / JetBrains)
108
+
109
+ Edit `~/.continue/config.json`:
110
+
111
+ ```json
112
+ {
113
+ "experimental": {
114
+ "modelContextProtocolServers": [
115
+ {
116
+ "transport": {
117
+ "type": "stdio",
118
+ "command": "npx",
119
+ "args": ["-y", "@otoinstall/mcp-server"],
120
+ "env": {
121
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here"
122
+ }
123
+ }
124
+ }
125
+ ]
126
+ }
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## ⚡ Zed
133
+
134
+ Edit `~/.config/zed/settings.json`:
135
+
136
+ ```json
137
+ {
138
+ "context_servers": {
139
+ "otoinstall": {
140
+ "command": {
141
+ "path": "npx",
142
+ "args": ["-y", "@otoinstall/mcp-server"],
143
+ "env": {
144
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here"
145
+ }
146
+ }
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 🦘 Roo Code
155
+
156
+ `.roo/mcp.json`:
157
+
158
+ ```json
159
+ {
160
+ "mcpServers": {
161
+ "otoinstall": {
162
+ "command": "npx",
163
+ "args": ["-y", "@otoinstall/mcp-server"],
164
+ "env": {
165
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here"
166
+ }
167
+ }
168
+ }
169
+ }
170
+ ```
171
+
172
+ ---
173
+
174
+ ## 🔧 Antigravity (Google Gemini)
175
+
176
+ Add to your MCP configuration:
177
+
178
+ ```json
179
+ {
180
+ "mcpServers": {
181
+ "otoinstall": {
182
+ "command": "npx",
183
+ "args": ["-y", "@otoinstall/mcp-server"],
184
+ "env": {
185
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here"
186
+ }
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 🏗️ Any MCP-Compatible Tool
195
+
196
+ The universal configuration pattern:
197
+
198
+ ```json
199
+ {
200
+ "command": "npx",
201
+ "args": ["-y", "@otoinstall/mcp-server"],
202
+ "env": {
203
+ "OTOINSTALL_API_KEY": "oi_live_your_key_here",
204
+ "OTOINSTALL_BASE_URL": "https://otoinstall.com"
205
+ }
206
+ }
207
+ ```
208
+
209
+ ---
210
+
211
+ ## 🛠️ Available Tools
212
+
213
+ | Tool | Description |
214
+ |---|---|
215
+ | `deploy_project` | Zip & deploy a project directory to a live server |
216
+ | `deploy_zip` | Deploy an existing ZIP file |
217
+ | `check_deploy_status` | Check deployment progress and status |
218
+ | `get_deploy_logs` | View detailed deployment logs |
219
+ | `list_projects` | List all your deployments |
220
+ | `list_servers` | List configured server credentials |
221
+ | `whoami` | Check API key owner and permissions |
222
+
223
+ ---
224
+
225
+ ## 💬 Usage Examples
226
+
227
+ ### Deploy from Claude
228
+
229
+ ```
230
+ You: "Deploy this project to my server"
231
+ Claude: I'll deploy the project. First, let me check your servers.
232
+ [calls list_servers]
233
+ You have 1 server: [ID: 1] MyVPS — sftp://user@myserver.com
234
+ [calls deploy_project with directory and credential_id=1]
235
+ ✅ Deployment started! Deploy ID: 01HYJ3R8KQFG...
236
+ [calls check_deploy_status]
237
+ 🎉 Deployment completed! Your site is live at https://mysite.com
238
+ ```
239
+
240
+ ### Deploy from Cursor
241
+
242
+ ```
243
+ You: "Publish this to production"
244
+ Cursor: [calls deploy_project]
245
+ ✅ Your project has been deployed!
246
+ 🌐 Live at: https://yourproject.com
247
+ ```
248
+
249
+ ---
250
+
251
+ ## 🔐 Environment Variables
252
+
253
+ | Variable | Required | Default | Description |
254
+ |---|---|---|---|
255
+ | `OTOINSTALL_API_KEY` | ✅ | — | Your OtoInstall API key |
256
+ | `OTOINSTALL_BASE_URL` | ❌ | `https://otoinstall.com` | API base URL |
257
+
258
+ ---
259
+
260
+ ## 📦 Local Development
261
+
262
+ ```bash
263
+ git clone https://github.com/otoinstall/mcp-server
264
+ cd mcp-server
265
+ npm install
266
+ npm run build
267
+ ```
268
+
269
+ Test with MCP Inspector:
270
+ ```bash
271
+ npx @modelcontextprotocol/inspector node dist/index.js
272
+ ```
273
+
274
+ ---
275
+
276
+ ## License
277
+
278
+ MIT © OtoInstall
@@ -0,0 +1,41 @@
1
+ /**
2
+ * OtoInstall API Client
3
+ * Handles all HTTP communication with the OtoInstall REST API.
4
+ */
5
+ export declare class OtoInstallClient {
6
+ private apiKey;
7
+ private baseUrl;
8
+ constructor(apiKey: string, baseUrl: string);
9
+ private get headers();
10
+ private request;
11
+ /**
12
+ * Deploy a ZIP file
13
+ */
14
+ deploy(zipPath: string, options: {
15
+ credential_id: number;
16
+ remote_path?: string;
17
+ target_url?: string;
18
+ project_type?: string;
19
+ }): Promise<any>;
20
+ /**
21
+ * Get deployment status
22
+ */
23
+ getDeployStatus(deployId: string): Promise<any>;
24
+ /**
25
+ * Get deployment logs
26
+ */
27
+ getDeployLogs(deployId: string): Promise<any>;
28
+ /**
29
+ * List projects/deployments
30
+ */
31
+ listProjects(status?: string, perPage?: number): Promise<any>;
32
+ /**
33
+ * List server credentials
34
+ */
35
+ listCredentials(): Promise<any>;
36
+ /**
37
+ * Get current user info
38
+ */
39
+ me(): Promise<any>;
40
+ }
41
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAK3C,OAAO,KAAK,OAAO,GAKlB;YAEa,OAAO;IA0BrB;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QACrC,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GAAG,OAAO,CAAC,GAAG,CAAC;IA+BhB;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAIrD;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAInD;;OAEG;IACG,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW,GAAG,OAAO,CAAC,GAAG,CAAC;IAOvE;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC;IAIrC;;OAEG;IACG,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC;CAGzB"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * OtoInstall API Client
3
+ * Handles all HTTP communication with the OtoInstall REST API.
4
+ */
5
+ import { readFileSync } from "fs";
6
+ import { basename } from "path";
7
+ export class OtoInstallClient {
8
+ apiKey;
9
+ baseUrl;
10
+ constructor(apiKey, baseUrl) {
11
+ this.apiKey = apiKey;
12
+ this.baseUrl = baseUrl.replace(/\/$/, "");
13
+ }
14
+ get headers() {
15
+ return {
16
+ Authorization: `Bearer ${this.apiKey}`,
17
+ Accept: "application/json",
18
+ };
19
+ }
20
+ async request(method, endpoint, body) {
21
+ const url = `${this.baseUrl}/api/v1${endpoint}`;
22
+ const opts = {
23
+ method,
24
+ headers: this.headers,
25
+ };
26
+ if (body && !(body instanceof FormData)) {
27
+ opts.headers["Content-Type"] = "application/json";
28
+ opts.body = JSON.stringify(body);
29
+ }
30
+ else if (body instanceof FormData) {
31
+ opts.body = body;
32
+ }
33
+ const response = await fetch(url, opts);
34
+ const data = await response.json();
35
+ if (!response.ok) {
36
+ const msg = data?.error?.message ?? `HTTP ${response.status}`;
37
+ throw new Error(msg);
38
+ }
39
+ return data;
40
+ }
41
+ /**
42
+ * Deploy a ZIP file
43
+ */
44
+ async deploy(zipPath, options) {
45
+ const fileBuffer = readFileSync(zipPath);
46
+ const fileName = basename(zipPath);
47
+ const fileBlob = new Blob([fileBuffer], { type: "application/zip" });
48
+ const form = new FormData();
49
+ form.append("file", fileBlob, fileName);
50
+ form.append("credential_id", String(options.credential_id));
51
+ if (options.remote_path)
52
+ form.append("remote_path", options.remote_path);
53
+ if (options.target_url)
54
+ form.append("target_url", options.target_url);
55
+ if (options.project_type)
56
+ form.append("project_type", options.project_type);
57
+ const url = `${this.baseUrl}/api/v1/deploy`;
58
+ const response = await fetch(url, {
59
+ method: "POST",
60
+ headers: {
61
+ Authorization: `Bearer ${this.apiKey}`,
62
+ Accept: "application/json",
63
+ },
64
+ body: form,
65
+ });
66
+ const data = await response.json();
67
+ if (!response.ok) {
68
+ throw new Error(data?.error?.message ?? `HTTP ${response.status}`);
69
+ }
70
+ return data;
71
+ }
72
+ /**
73
+ * Get deployment status
74
+ */
75
+ async getDeployStatus(deployId) {
76
+ return this.request("GET", `/deploy/${deployId}/status`);
77
+ }
78
+ /**
79
+ * Get deployment logs
80
+ */
81
+ async getDeployLogs(deployId) {
82
+ return this.request("GET", `/deploy/${deployId}/logs`);
83
+ }
84
+ /**
85
+ * List projects/deployments
86
+ */
87
+ async listProjects(status, perPage = 10) {
88
+ const params = new URLSearchParams();
89
+ if (status)
90
+ params.set("status", status);
91
+ params.set("per_page", String(perPage));
92
+ return this.request("GET", `/projects?${params.toString()}`);
93
+ }
94
+ /**
95
+ * List server credentials
96
+ */
97
+ async listCredentials() {
98
+ return this.request("GET", "/credentials");
99
+ }
100
+ /**
101
+ * Get current user info
102
+ */
103
+ async me() {
104
+ return this.request("GET", "/me");
105
+ }
106
+ }
107
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OtoInstall MCP Server
4
+ *
5
+ * Deploy projects directly from any MCP-compatible AI tool:
6
+ * Claude Desktop, Cursor, Windsurf, Cline, Continue, Zed, and more.
7
+ *
8
+ * Setup: Set OTOINSTALL_API_KEY and optionally OTOINSTALL_BASE_URL env vars.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
package/dist/index.js ADDED
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OtoInstall MCP Server
4
+ *
5
+ * Deploy projects directly from any MCP-compatible AI tool:
6
+ * Claude Desktop, Cursor, Windsurf, Cline, Continue, Zed, and more.
7
+ *
8
+ * Setup: Set OTOINSTALL_API_KEY and optionally OTOINSTALL_BASE_URL env vars.
9
+ */
10
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
11
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
+ import { z } from "zod";
13
+ import { OtoInstallClient } from "./api-client.js";
14
+ import { zipDirectory } from "./zip-utils.js";
15
+ import { existsSync } from "fs";
16
+ import { resolve, basename } from "path";
17
+ // ─── Configuration ───
18
+ const API_KEY = process.env.OTOINSTALL_API_KEY ?? "";
19
+ const BASE_URL = process.env.OTOINSTALL_BASE_URL ?? "https://otoinstall.com";
20
+ if (!API_KEY) {
21
+ console.error("❌ OTOINSTALL_API_KEY environment variable is required.");
22
+ console.error(" Get your key at: https://otoinstall.com/account/api-keys");
23
+ process.exit(1);
24
+ }
25
+ const client = new OtoInstallClient(API_KEY, BASE_URL);
26
+ // ─── MCP Server ───
27
+ const server = new McpServer({
28
+ name: "otoinstall",
29
+ version: "1.0.0",
30
+ });
31
+ // ════════════════════════════════════════════════════════════════
32
+ // TOOL 1: deploy_project
33
+ // ════════════════════════════════════════════════════════════════
34
+ server.tool("deploy_project", "Deploy a project to a live server. Zips the specified directory and uploads it to OtoInstall for automated security scanning, auto-fixing, and deployment via FTP/SFTP/SSH.", {
35
+ directory: z.string().describe("Absolute path to the project directory to deploy"),
36
+ credential_id: z.number().describe("Server credential ID to deploy to (use list_servers to find IDs)"),
37
+ remote_path: z.string().optional().describe("Remote path on the server (optional, uses credential default)"),
38
+ target_url: z.string().optional().describe("Expected URL of the deployed site (optional)"),
39
+ project_type: z.enum(["auto", "laravel", "wordpress", "react", "vue", "nextjs", "html", "php"]).optional().describe("Project type hint (default: auto-detect)"),
40
+ }, async ({ directory, credential_id, remote_path, target_url, project_type }) => {
41
+ try {
42
+ // Validate directory exists
43
+ const absDir = resolve(directory);
44
+ if (!existsSync(absDir)) {
45
+ return { content: [{ type: "text", text: `❌ Directory not found: ${absDir}` }] };
46
+ }
47
+ // Zip the directory
48
+ const zipPath = await zipDirectory(absDir);
49
+ const zipName = `${basename(absDir)}.zip`;
50
+ // Deploy via API
51
+ const result = await client.deploy(zipPath, {
52
+ credential_id,
53
+ remote_path,
54
+ target_url,
55
+ project_type: project_type ?? "auto",
56
+ });
57
+ // Clean up temp zip
58
+ try {
59
+ (await import("fs")).unlinkSync(zipPath);
60
+ }
61
+ catch { }
62
+ return {
63
+ content: [{
64
+ type: "text",
65
+ text: [
66
+ `✅ Deployment started!`,
67
+ ``,
68
+ `📦 Deploy ID: ${result.deploy_id}`,
69
+ `📊 Status: ${result.status}`,
70
+ `🔗 Status URL: ${result.links?.status ?? "N/A"}`,
71
+ `🌐 Web Dashboard: ${result.links?.web ?? "N/A"}`,
72
+ ``,
73
+ `Use check_deploy_status with deploy_id "${result.deploy_id}" to monitor progress.`,
74
+ ].join("\n"),
75
+ }],
76
+ };
77
+ }
78
+ catch (error) {
79
+ return {
80
+ content: [{ type: "text", text: `❌ Deploy failed: ${error.message}` }],
81
+ isError: true,
82
+ };
83
+ }
84
+ });
85
+ // ════════════════════════════════════════════════════════════════
86
+ // TOOL 2: deploy_zip
87
+ // ════════════════════════════════════════════════════════════════
88
+ server.tool("deploy_zip", "Deploy an existing ZIP file to a live server via OtoInstall. Use this when you already have a ZIP file ready.", {
89
+ zip_path: z.string().describe("Absolute path to the ZIP file to deploy"),
90
+ credential_id: z.number().describe("Server credential ID to deploy to"),
91
+ remote_path: z.string().optional().describe("Remote path on the server"),
92
+ target_url: z.string().optional().describe("Expected URL of the deployed site"),
93
+ project_type: z.enum(["auto", "laravel", "wordpress", "react", "vue", "nextjs", "html", "php"]).optional().describe("Project type hint"),
94
+ }, async ({ zip_path, credential_id, remote_path, target_url, project_type }) => {
95
+ try {
96
+ const absPath = resolve(zip_path);
97
+ if (!existsSync(absPath)) {
98
+ return { content: [{ type: "text", text: `❌ ZIP file not found: ${absPath}` }] };
99
+ }
100
+ const result = await client.deploy(absPath, {
101
+ credential_id,
102
+ remote_path,
103
+ target_url,
104
+ project_type: project_type ?? "auto",
105
+ });
106
+ return {
107
+ content: [{
108
+ type: "text",
109
+ text: [
110
+ `✅ Deployment started from ZIP!`,
111
+ ``,
112
+ `📦 Deploy ID: ${result.deploy_id}`,
113
+ `📊 Status: ${result.status}`,
114
+ `🔗 Track: ${result.links?.status ?? "N/A"}`,
115
+ ].join("\n"),
116
+ }],
117
+ };
118
+ }
119
+ catch (error) {
120
+ return {
121
+ content: [{ type: "text", text: `❌ Deploy failed: ${error.message}` }],
122
+ isError: true,
123
+ };
124
+ }
125
+ });
126
+ // ════════════════════════════════════════════════════════════════
127
+ // TOOL 3: check_deploy_status
128
+ // ════════════════════════════════════════════════════════════════
129
+ server.tool("check_deploy_status", "Check the current status of a deployment. Returns progress percentage, current phase, and any errors.", {
130
+ deploy_id: z.string().describe("The deployment ULID returned from deploy_project or deploy_zip"),
131
+ }, async ({ deploy_id }) => {
132
+ try {
133
+ const status = await client.getDeployStatus(deploy_id);
134
+ const statusEmoji = {
135
+ queued: "⏳", scanning: "🔍", detecting: "🔎",
136
+ compatibility_check: "🧪", fixing: "🔧",
137
+ local_testing: "🧪", deploying: "🚀",
138
+ verifying: "✅", completed: "🎉",
139
+ scan_failed: "❌", fix_failed: "❌",
140
+ deploy_failed: "❌", local_test_failed: "❌",
141
+ awaiting_user: "⏸️",
142
+ };
143
+ const emoji = statusEmoji[status.status] ?? "📊";
144
+ let text = [
145
+ `${emoji} Deployment Status`,
146
+ ``,
147
+ `📦 Deploy ID: ${status.deploy_id}`,
148
+ `📊 Status: ${status.status}`,
149
+ `📈 Progress: ${status.progress}%`,
150
+ ];
151
+ if (status.project_type)
152
+ text.push(`📁 Type: ${status.project_type}`);
153
+ if (status.target_url)
154
+ text.push(`🌐 URL: ${status.target_url}`);
155
+ if (status.security_score !== null && status.security_score !== undefined) {
156
+ text.push(`🛡️ Security Score: ${status.security_score}/100`);
157
+ }
158
+ if (status.started_at)
159
+ text.push(`⏱️ Started: ${status.started_at}`);
160
+ if (status.completed_at)
161
+ text.push(`✅ Completed: ${status.completed_at}`);
162
+ if (status.error)
163
+ text.push(`\n❌ Error: ${status.error}`);
164
+ return { content: [{ type: "text", text: text.join("\n") }] };
165
+ }
166
+ catch (error) {
167
+ return {
168
+ content: [{ type: "text", text: `❌ Failed to check status: ${error.message}` }],
169
+ isError: true,
170
+ };
171
+ }
172
+ });
173
+ // ════════════════════════════════════════════════════════════════
174
+ // TOOL 4: get_deploy_logs
175
+ // ════════════════════════════════════════════════════════════════
176
+ server.tool("get_deploy_logs", "Retrieve the detailed deployment logs for a specific deployment.", {
177
+ deploy_id: z.string().describe("The deployment ULID"),
178
+ }, async ({ deploy_id }) => {
179
+ try {
180
+ const data = await client.getDeployLogs(deploy_id);
181
+ if (!data.logs || data.logs.length === 0) {
182
+ return { content: [{ type: "text", text: `📋 No logs yet for deployment ${deploy_id}.` }] };
183
+ }
184
+ const logText = data.logs.map((log) => {
185
+ const levelEmoji = {
186
+ info: "ℹ️", warning: "⚠️", error: "❌", success: "✅", debug: "🔍"
187
+ };
188
+ return `${levelEmoji[log.level] ?? "•"} [${log.time}] ${log.message}`;
189
+ }).join("\n");
190
+ return {
191
+ content: [{ type: "text", text: `📋 Deployment Logs (${deploy_id}):\n\n${logText}` }],
192
+ };
193
+ }
194
+ catch (error) {
195
+ return {
196
+ content: [{ type: "text", text: `❌ Failed to get logs: ${error.message}` }],
197
+ isError: true,
198
+ };
199
+ }
200
+ });
201
+ // ════════════════════════════════════════════════════════════════
202
+ // TOOL 5: list_projects
203
+ // ════════════════════════════════════════════════════════════════
204
+ server.tool("list_projects", "List all deployments (projects) for the current user. Shows status, progress, and URLs.", {
205
+ status: z.string().optional().describe("Filter by status: queued, scanning, deploying, completed, etc."),
206
+ per_page: z.number().optional().describe("Results per page (default: 10)"),
207
+ }, async ({ status, per_page }) => {
208
+ try {
209
+ const data = await client.listProjects(status, per_page ?? 10);
210
+ if (!data.data || data.data.length === 0) {
211
+ return { content: [{ type: "text", text: "📭 No deployments found." }] };
212
+ }
213
+ const projectList = data.data.map((p) => {
214
+ return [
215
+ `• ${p.filename} (${p.deploy_id})`,
216
+ ` Status: ${p.status} | Progress: ${p.progress}%`,
217
+ p.target_url ? ` URL: ${p.target_url}` : null,
218
+ ` Created: ${p.created_at}`,
219
+ ].filter(Boolean).join("\n");
220
+ }).join("\n\n");
221
+ return {
222
+ content: [{
223
+ type: "text",
224
+ text: `📦 Deployments (${data.pagination.total} total):\n\n${projectList}`,
225
+ }],
226
+ };
227
+ }
228
+ catch (error) {
229
+ return {
230
+ content: [{ type: "text", text: `❌ Failed to list projects: ${error.message}` }],
231
+ isError: true,
232
+ };
233
+ }
234
+ });
235
+ // ════════════════════════════════════════════════════════════════
236
+ // TOOL 6: list_servers
237
+ // ════════════════════════════════════════════════════════════════
238
+ server.tool("list_servers", "List all configured server credentials. Returns server IDs needed for deploy_project.", {}, async () => {
239
+ try {
240
+ const data = await client.listCredentials();
241
+ if (!data.data || data.data.length === 0) {
242
+ return {
243
+ content: [{
244
+ type: "text",
245
+ text: "📭 No servers configured. Add servers at your OtoInstall dashboard.",
246
+ }],
247
+ };
248
+ }
249
+ const serverList = data.data.map((s) => {
250
+ return `• [ID: ${s.id}] ${s.label} — ${s.protocol}://${s.username}@${s.host}:${s.port}${s.remote_path ?? ""}`;
251
+ }).join("\n");
252
+ return {
253
+ content: [{
254
+ type: "text",
255
+ text: `🖥️ Configured Servers:\n\n${serverList}\n\nUse the ID number with deploy_project's credential_id parameter.`,
256
+ }],
257
+ };
258
+ }
259
+ catch (error) {
260
+ return {
261
+ content: [{ type: "text", text: `❌ Failed to list servers: ${error.message}` }],
262
+ isError: true,
263
+ };
264
+ }
265
+ });
266
+ // ════════════════════════════════════════════════════════════════
267
+ // TOOL 7: whoami
268
+ // ════════════════════════════════════════════════════════════════
269
+ server.tool("whoami", "Check the current API key owner and permissions.", {}, async () => {
270
+ try {
271
+ const data = await client.me();
272
+ return {
273
+ content: [{
274
+ type: "text",
275
+ text: [
276
+ `👤 OtoInstall Account`,
277
+ ``,
278
+ `Name: ${data.user.name}`,
279
+ `Email: ${data.user.email}`,
280
+ ``,
281
+ `🔑 API Key: ${data.api_key.prefix}`,
282
+ `📋 Scopes: ${data.api_key.scopes.join(", ")}`,
283
+ `📊 Rate Limit: ${data.api_key.rate_limit}/hour`,
284
+ data.api_key.last_used ? `⏱️ Last Used: ${data.api_key.last_used}` : null,
285
+ ].filter(Boolean).join("\n"),
286
+ }],
287
+ };
288
+ }
289
+ catch (error) {
290
+ return {
291
+ content: [{ type: "text", text: `❌ Auth failed: ${error.message}` }],
292
+ isError: true,
293
+ };
294
+ }
295
+ });
296
+ // ─── Start Server ───
297
+ async function main() {
298
+ const transport = new StdioServerTransport();
299
+ await server.connect(transport);
300
+ console.error("🚀 OtoInstall MCP Server running (stdio transport)");
301
+ }
302
+ main().catch((error) => {
303
+ console.error("Fatal error:", error);
304
+ process.exit(1);
305
+ });
306
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ZIP Utilities
3
+ * Creates ZIP archives from directories for deployment.
4
+ */
5
+ /**
6
+ * Zip a directory and return the path to the temporary ZIP file.
7
+ * Excludes common non-deployable files (node_modules, .git, etc.)
8
+ */
9
+ export declare function zipDirectory(dirPath: string): Promise<string>;
10
+ //# sourceMappingURL=zip-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-utils.d.ts","sourceRoot":"","sources":["../src/zip-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;;GAGG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+CnE"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * ZIP Utilities
3
+ * Creates ZIP archives from directories for deployment.
4
+ */
5
+ import archiver from "archiver";
6
+ import { createWriteStream, mkdtempSync } from "fs";
7
+ import { tmpdir } from "os";
8
+ import { join, basename } from "path";
9
+ /**
10
+ * Zip a directory and return the path to the temporary ZIP file.
11
+ * Excludes common non-deployable files (node_modules, .git, etc.)
12
+ */
13
+ export async function zipDirectory(dirPath) {
14
+ const tempDir = mkdtempSync(join(tmpdir(), "otoinstall-"));
15
+ const zipPath = join(tempDir, `${basename(dirPath)}.zip`);
16
+ return new Promise((resolve, reject) => {
17
+ const output = createWriteStream(zipPath);
18
+ const archive = archiver("zip", { zlib: { level: 6 } });
19
+ output.on("close", () => resolve(zipPath));
20
+ archive.on("error", (err) => reject(err));
21
+ archive.on("warning", (err) => {
22
+ if (err.code !== "ENOENT")
23
+ reject(err);
24
+ });
25
+ archive.pipe(output);
26
+ // Add directory contents, excluding heavy/unnecessary files
27
+ archive.glob("**/*", {
28
+ cwd: dirPath,
29
+ dot: true,
30
+ ignore: [
31
+ "node_modules/**",
32
+ ".git/**",
33
+ ".svn/**",
34
+ ".hg/**",
35
+ ".DS_Store",
36
+ "Thumbs.db",
37
+ "*.log",
38
+ ".env.local",
39
+ ".env.*.local",
40
+ "vendor/**",
41
+ "__pycache__/**",
42
+ "*.pyc",
43
+ ".next/**",
44
+ "dist/**",
45
+ "build/**",
46
+ ".cache/**",
47
+ "coverage/**",
48
+ ".idea/**",
49
+ ".vscode/**",
50
+ "*.swp",
51
+ "*.swo",
52
+ ],
53
+ });
54
+ archive.finalize();
55
+ });
56
+ }
57
+ //# sourceMappingURL=zip-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-utils.js","sourceRoot":"","sources":["../src/zip-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEtC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe;IAChD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE1D,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAExD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;YAC5B,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAErB,4DAA4D;QAC5D,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;YACnB,GAAG,EAAE,OAAO;YACZ,GAAG,EAAE,IAAI;YACT,MAAM,EAAE;gBACN,iBAAiB;gBACjB,SAAS;gBACT,SAAS;gBACT,QAAQ;gBACR,WAAW;gBACX,WAAW;gBACX,OAAO;gBACP,YAAY;gBACZ,cAAc;gBACd,WAAW;gBACX,gBAAgB;gBAChB,OAAO;gBACP,UAAU;gBACV,SAAS;gBACT,UAAU;gBACV,WAAW;gBACX,aAAa;gBACb,UAAU;gBACV,YAAY;gBACZ,OAAO;gBACP,OAAO;aACR;SACF,CAAC,CAAC;QAEH,OAAO,CAAC,QAAQ,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "otoinstall-mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "OtoInstall MCP Server — Deploy projects from Claude, Cursor, Windsurf, Cline, Zed, and any MCP-compatible AI tool",
5
+ "keywords": ["mcp", "otoinstall", "deploy", "claude", "cursor", "windsurf", "cline", "ai-tools", "vibecoding"],
6
+ "license": "MIT",
7
+ "author": "OtoInstall <hello@otoinstall.com>",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/ovkdigital/otoinstall-tools.git",
11
+ "directory": "packages/mcp-server"
12
+ },
13
+ "homepage": "https://otoinstall.com",
14
+ "bugs": "https://github.com/ovkdigital/otoinstall/issues",
15
+ "type": "module",
16
+ "bin": {
17
+ "otoinstall-mcp": "./dist/index.js"
18
+ },
19
+ "main": "./dist/index.js",
20
+ "files": ["dist", "README.md"],
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "dev": "tsc --watch",
24
+ "start": "node dist/index.js",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "dependencies": {
28
+ "@modelcontextprotocol/sdk": "^1.12.0",
29
+ "archiver": "^7.0.1",
30
+ "node-fetch": "^3.3.2",
31
+ "form-data": "^4.0.1",
32
+ "zod": "^3.23.8"
33
+ },
34
+ "devDependencies": {
35
+ "@types/archiver": "^6.0.3",
36
+ "@types/node": "^22.10.0",
37
+ "typescript": "^5.7.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ }
42
+ }