impreza-mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Impreza Host
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # impreza-mcp
2
+
3
+ [Model Context Protocol](https://modelcontextprotocol.io) server for
4
+ [Impreza Host](https://imprezahost.com). Lets AI coding tools (Claude
5
+ Code, Cursor, Codex CLI, Continue, Zed, ...) deploy customer-built
6
+ apps to managed Impreza VPSes without leaving the chat.
7
+
8
+ When you say "deploy this for me" to Claude with this MCP server
9
+ loaded, Claude calls `impreza_deploy_custom` directly — packages your
10
+ project, uploads it, builds + runs on your Impreza VPS, and reports
11
+ back the URL.
12
+
13
+ ## Status
14
+
15
+ **0.1.0 — full surface live.** All 10 tools shipped + a setup wizard
16
+ that generates ready-to-paste config snippets for 5 AI tools.
17
+ Roadmap context lives in
18
+ [`docs/PLAN_AI_INTEGRATION_ROADMAP.md`](https://git.imprezahost.com/impreza/impreza-platform/-/blob/main/docs/PLAN_AI_INTEGRATION_ROADMAP.md)
19
+ of the impreza-platform repo.
20
+
21
+ | Tool | Wraps |
22
+ |------|-------|
23
+ | `impreza_list_servers` | `GET /v1/platform/servers` |
24
+ | `impreza_list_apps` | `GET /v1/platform/apps` |
25
+ | `impreza_list_deployments` | `GET /v1/platform/deployments` + `/custom` (merged) |
26
+ | `impreza_deploy_custom` | `POST /v1/platform/deployments/custom` (3 modes) |
27
+ | `impreza_deploy_catalog_app` | `POST /v1/platform/deployments` |
28
+ | `impreza_uninstall_deployment` | `POST .../uninstall` |
29
+ | `impreza_get_logs` | `POST .../logs` (sync tail, last N lines) |
30
+ | `impreza_restart_deployment` | `POST .../restart` |
31
+ | `impreza_add_onion` | `POST .../onion/add` |
32
+ | `impreza_change_domain` | `POST .../domain` |
33
+
34
+ ## Install + setup
35
+
36
+ ### Prerequisites
37
+
38
+ - Node ≥ 20
39
+ - An Impreza Host account with an API key + secret
40
+ (clientarea → API Keys; the IP of the machine running this MCP
41
+ server must be whitelisted under the key)
42
+
43
+ ### One-shot via `npx`
44
+
45
+ No global install needed — `npx impreza-mcp` works.
46
+
47
+ ### Or install globally
48
+
49
+ ```sh
50
+ npm install -g impreza-mcp
51
+ ```
52
+
53
+ ### Get a ready-to-paste config snippet
54
+
55
+ The fastest path: ask the binary itself.
56
+
57
+ ```sh
58
+ npx impreza-mcp setup --tool claude-code
59
+ # also: cursor | continue | zed | codex-cli
60
+ ```
61
+
62
+ The wizard prints the JSON block to drop into your AI tool's MCP
63
+ config + the exact file path + the post-config step (usually "fully
64
+ quit + re-open the AI tool"). It does NOT write to disk — paste it
65
+ yourself so you don't accidentally clobber an existing config with
66
+ other MCP servers.
67
+
68
+ ### Or wire it in manually
69
+
70
+ **Claude Code** — add to `~/Library/Application Support/Claude/claude_desktop_config.json`
71
+ (macOS) or `%APPDATA%/Claude/claude_desktop_config.json` (Windows):
72
+
73
+ ```json
74
+ {
75
+ "mcpServers": {
76
+ "impreza": {
77
+ "command": "npx",
78
+ "args": ["-y", "impreza-mcp"],
79
+ "env": {
80
+ "IMPREZA_API_KEY": "imp_...",
81
+ "IMPREZA_API_SECRET": "..."
82
+ }
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ Restart Claude Code. The tools appear under the MCP icon.
89
+
90
+ **Cursor** — add to `~/.cursor/mcp.json` (same shape as above).
91
+
92
+ **Continue** — add to `~/.continue/config.json`:
93
+
94
+ ```json
95
+ {
96
+ "experimental": {
97
+ "modelContextProtocolServers": [
98
+ {
99
+ "transport": {
100
+ "type": "stdio",
101
+ "command": "npx",
102
+ "args": ["-y", "impreza-mcp"],
103
+ "env": {
104
+ "IMPREZA_API_KEY": "imp_...",
105
+ "IMPREZA_API_SECRET": "..."
106
+ }
107
+ }
108
+ }
109
+ ]
110
+ }
111
+ }
112
+ ```
113
+
114
+ **Zed** — add to your settings:
115
+
116
+ ```json
117
+ {
118
+ "context_servers": {
119
+ "impreza": {
120
+ "command": {
121
+ "path": "npx",
122
+ "args": ["-y", "impreza-mcp"],
123
+ "env": {
124
+ "IMPREZA_API_KEY": "imp_...",
125
+ "IMPREZA_API_SECRET": "..."
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ ```
132
+
133
+ ## Usage in chat
134
+
135
+ After setup, talk to your AI naturally:
136
+
137
+ > *"List my Impreza servers."* → calls `impreza_list_servers`
138
+ >
139
+ > *"Deploy this directory to my Impreza VPS, expose via .onion."* →
140
+ > packages the cwd as a Dockerfile-mode custom deploy, uploads, deploys
141
+ > with `onion=true`, reports the .onion address.
142
+ >
143
+ > *"What apps are running on my agent?"* → calls
144
+ > `impreza_list_deployments` filtered to the right server.
145
+
146
+ ## Auth + security
147
+
148
+ `IMPREZA_API_KEY` + `IMPREZA_API_SECRET` live in the AI tool's MCP
149
+ config env — not in any file on disk owned by `impreza-mcp` itself.
150
+ The MCP server holds the secret only in memory and only attaches it
151
+ as HTTP request headers.
152
+
153
+ The IP of the machine running this MCP server (almost always your
154
+ laptop) must be on the API key's whitelist. Manage the whitelist in
155
+ your Impreza clientarea.
156
+
157
+ ## Build
158
+
159
+ ```sh
160
+ npm install
161
+ npm run build
162
+ # dist/server.js is the entry point
163
+ ```
164
+
165
+ ## License
166
+
167
+ MIT — see `LICENSE`.
@@ -0,0 +1,104 @@
1
+ export interface ImprezaConfig {
2
+ baseURL: string;
3
+ apiKey: string;
4
+ apiSecret: string;
5
+ /** Wall-clock budget per HTTP call. Default 60s. */
6
+ timeoutMs?: number;
7
+ }
8
+ export declare class ImprezaClient {
9
+ private readonly baseURL;
10
+ private readonly apiKey;
11
+ private readonly apiSecret;
12
+ private readonly timeoutMs;
13
+ constructor(cfg: ImprezaConfig);
14
+ /**
15
+ * Authenticated GET. Decodes the standard envelope ({success, data,
16
+ * meta}) and returns the `data` payload typed as T. Throws on non-2xx
17
+ * or success=false.
18
+ */
19
+ get<T>(path: string, query?: Record<string, string>): Promise<T>;
20
+ /**
21
+ * Authenticated JSON POST. body is JSON.stringified; response decoded
22
+ * as envelope.
23
+ */
24
+ post<T>(path: string, body: unknown): Promise<T>;
25
+ /**
26
+ * Authenticated POST with raw binary body. Used for the Phase 12
27
+ * context upload (`POST /v1/platform/deployments/custom/contexts`)
28
+ * which accepts a gzip tarball as the raw body.
29
+ */
30
+ postRaw<T>(path: string, contentType: string, bytes: Uint8Array): Promise<T>;
31
+ private fetch;
32
+ private parseEnvelope;
33
+ }
34
+ export interface Server_ {
35
+ agent_id: string;
36
+ hostname: string;
37
+ origin: string;
38
+ service_id?: number | null;
39
+ status: string;
40
+ version?: string;
41
+ last_seen_at?: string;
42
+ }
43
+ export interface ServerList {
44
+ servers: Server_[];
45
+ total: number;
46
+ }
47
+ export interface App {
48
+ name: string;
49
+ display_name: string;
50
+ version: string;
51
+ category: string;
52
+ tags?: string[];
53
+ description?: string;
54
+ icon_url?: string;
55
+ }
56
+ export interface AppList {
57
+ apps: App[];
58
+ total: number;
59
+ }
60
+ export interface Deployment {
61
+ id: string;
62
+ app_name?: string;
63
+ app_version?: string;
64
+ name?: string;
65
+ mode?: string;
66
+ agent_id: string;
67
+ status: string;
68
+ domain?: string | null;
69
+ onion?: string | null;
70
+ image?: string;
71
+ cpus?: number;
72
+ memory_mb?: number;
73
+ vars?: Record<string, unknown>;
74
+ created_at: string;
75
+ last_health_at?: string | null;
76
+ last_error?: string | null;
77
+ }
78
+ export interface DeploymentList {
79
+ deployments: Deployment[];
80
+ total: number;
81
+ }
82
+ export interface CustomDeployContextUpload {
83
+ context_id: string;
84
+ sha256: string;
85
+ size_bytes: number;
86
+ expires_at: string;
87
+ }
88
+ /**
89
+ * Tar + gzip the given project directory into a temp file, return
90
+ * the bytes + the temp path (so the caller can delete it after
91
+ * upload). Excludes the usual suspects (.git, node_modules,
92
+ * __pycache__, etc.) baked into the same list the Go CLI uses.
93
+ *
94
+ * The tar is rooted at the project dir contents (entries are
95
+ * `Dockerfile`, `main.go`, etc., not `proj/Dockerfile`), matching
96
+ * what the agent's extractor expects.
97
+ */
98
+ export declare function tarProjectDir(projectDir: string): Promise<{
99
+ bytes: Uint8Array;
100
+ sizeBytes: number;
101
+ cleanup: () => Promise<void>;
102
+ }>;
103
+ /** Lowercase hex sha256 of the given bytes. */
104
+ export declare function sha256Hex(bytes: Uint8Array): string;
package/dist/client.js ADDED
@@ -0,0 +1,175 @@
1
+ // Tiny Impreza Host REST client. Hand-written to match the public
2
+ // OpenAPI surface in impreza-platform/specs/openapi-platform.yaml.
3
+ //
4
+ // Auth: standard X-API-Key + X-API-Secret headers, sourced from env.
5
+ // Network: native fetch (Node ≥ 20 has it). No retry / circuit-breaker
6
+ // in v1 — the AI client retries the tool call if it cares.
7
+ import { createHash } from 'node:crypto';
8
+ import { readFile, stat } from 'node:fs/promises';
9
+ import { tmpdir } from 'node:os';
10
+ import { join } from 'node:path';
11
+ import { createWriteStream } from 'node:fs';
12
+ import { unlink } from 'node:fs/promises';
13
+ import * as tar from 'tar';
14
+ export class ImprezaClient {
15
+ baseURL;
16
+ apiKey;
17
+ apiSecret;
18
+ timeoutMs;
19
+ constructor(cfg) {
20
+ this.baseURL = cfg.baseURL.replace(/\/+$/, '');
21
+ this.apiKey = cfg.apiKey;
22
+ this.apiSecret = cfg.apiSecret;
23
+ this.timeoutMs = cfg.timeoutMs ?? 60_000;
24
+ }
25
+ /**
26
+ * Authenticated GET. Decodes the standard envelope ({success, data,
27
+ * meta}) and returns the `data` payload typed as T. Throws on non-2xx
28
+ * or success=false.
29
+ */
30
+ async get(path, query) {
31
+ const url = new URL(this.baseURL + path);
32
+ if (query) {
33
+ for (const [k, v] of Object.entries(query)) {
34
+ if (v !== undefined && v !== '')
35
+ url.searchParams.set(k, v);
36
+ }
37
+ }
38
+ const res = await this.fetch(url, { method: 'GET' });
39
+ return this.parseEnvelope(res);
40
+ }
41
+ /**
42
+ * Authenticated JSON POST. body is JSON.stringified; response decoded
43
+ * as envelope.
44
+ */
45
+ async post(path, body) {
46
+ const res = await this.fetch(new URL(this.baseURL + path), {
47
+ method: 'POST',
48
+ headers: { 'Content-Type': 'application/json' },
49
+ body: JSON.stringify(body ?? {}),
50
+ });
51
+ return this.parseEnvelope(res);
52
+ }
53
+ /**
54
+ * Authenticated POST with raw binary body. Used for the Phase 12
55
+ * context upload (`POST /v1/platform/deployments/custom/contexts`)
56
+ * which accepts a gzip tarball as the raw body.
57
+ */
58
+ async postRaw(path, contentType, bytes) {
59
+ const res = await this.fetch(new URL(this.baseURL + path), {
60
+ method: 'POST',
61
+ headers: { 'Content-Type': contentType },
62
+ body: bytes,
63
+ });
64
+ return this.parseEnvelope(res);
65
+ }
66
+ async fetch(url, init) {
67
+ const ctrl = new AbortController();
68
+ const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
69
+ try {
70
+ const res = await fetch(url, {
71
+ ...init,
72
+ headers: {
73
+ Accept: 'application/json',
74
+ 'X-API-Key': this.apiKey,
75
+ 'X-API-Secret': this.apiSecret,
76
+ 'User-Agent': `impreza-mcp/${VERSION}`,
77
+ ...(init.headers ?? {}),
78
+ },
79
+ signal: ctrl.signal,
80
+ });
81
+ return res;
82
+ }
83
+ finally {
84
+ clearTimeout(timer);
85
+ }
86
+ }
87
+ async parseEnvelope(res) {
88
+ const text = await res.text();
89
+ let env;
90
+ try {
91
+ env = text ? JSON.parse(text) : {};
92
+ }
93
+ catch {
94
+ throw new Error(`HTTP ${res.status}: non-JSON response (${text.slice(0, 200)})`);
95
+ }
96
+ if (!res.ok || env.success === false || env.error) {
97
+ const code = env.error?.code ?? `HTTP_${res.status}`;
98
+ const msg = env.error?.message ?? `request failed (HTTP ${res.status})`;
99
+ const reqId = env.meta?.request_id ? ` [req=${env.meta.request_id}]` : '';
100
+ throw new Error(`${code}: ${msg}${reqId}`);
101
+ }
102
+ return env.data ?? undefined;
103
+ }
104
+ }
105
+ /** Hard-coded version stamp — bumped per release. */
106
+ const VERSION = '0.1.0';
107
+ // ─────────────────────────────────────────────────────────────────────
108
+ // Tarball helper — used by the Dockerfile-mode upload path
109
+ // ─────────────────────────────────────────────────────────────────────
110
+ /**
111
+ * Tar + gzip the given project directory into a temp file, return
112
+ * the bytes + the temp path (so the caller can delete it after
113
+ * upload). Excludes the usual suspects (.git, node_modules,
114
+ * __pycache__, etc.) baked into the same list the Go CLI uses.
115
+ *
116
+ * The tar is rooted at the project dir contents (entries are
117
+ * `Dockerfile`, `main.go`, etc., not `proj/Dockerfile`), matching
118
+ * what the agent's extractor expects.
119
+ */
120
+ export async function tarProjectDir(projectDir) {
121
+ const info = await stat(projectDir);
122
+ if (!info.isDirectory()) {
123
+ throw new Error(`${projectDir} is not a directory`);
124
+ }
125
+ const tmpPath = join(tmpdir(), `impreza-mcp-ctx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.tar.gz`);
126
+ // Stream-tar into the temp file, then read back as bytes.
127
+ await new Promise((resolve, reject) => {
128
+ const out = createWriteStream(tmpPath);
129
+ out.on('error', reject);
130
+ out.on('finish', resolve);
131
+ tar
132
+ .create({
133
+ gzip: true,
134
+ cwd: projectDir,
135
+ // Exclude common noise that bloats the upload or contains
136
+ // host-specific paths. Match basenames against the bake-in set.
137
+ filter: (path) => !isExcluded(path),
138
+ }, ['.'])
139
+ .pipe(out);
140
+ });
141
+ const bytes = await readFile(tmpPath);
142
+ return {
143
+ bytes,
144
+ sizeBytes: bytes.byteLength,
145
+ cleanup: async () => {
146
+ try {
147
+ await unlink(tmpPath);
148
+ }
149
+ catch {
150
+ /* best effort */
151
+ }
152
+ },
153
+ };
154
+ }
155
+ const EXCLUDED_DIRS = new Set(['.git', '.svn', '.hg', '.bzr', 'node_modules', '__pycache__', '.venv', 'venv', '.impreza']);
156
+ const EXCLUDED_FILES = new Set(['.DS_Store', 'Thumbs.db']);
157
+ function isExcluded(relPath) {
158
+ const normalized = relPath.replace(/^\.[\\/]+/, '').replace(/\\/g, '/');
159
+ const parts = normalized.split('/').filter((p) => p && p !== '.');
160
+ for (const p of parts) {
161
+ if (EXCLUDED_DIRS.has(p))
162
+ return true;
163
+ }
164
+ const base = parts[parts.length - 1] ?? '';
165
+ if (EXCLUDED_FILES.has(base))
166
+ return true;
167
+ if (base.endsWith('.pyc'))
168
+ return true;
169
+ return false;
170
+ }
171
+ /** Lowercase hex sha256 of the given bytes. */
172
+ export function sha256Hex(bytes) {
173
+ return createHash('sha256').update(bytes).digest('hex');
174
+ }
175
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/server.js ADDED
@@ -0,0 +1,433 @@
1
+ #!/usr/bin/env node
2
+ //
3
+ // impreza-mcp — Model Context Protocol server for Impreza Host.
4
+ //
5
+ // Boots over stdio so AI tools (Claude Code, Cursor, Codex, Continue,
6
+ // Zed, ...) can attach via the standard `command + args` MCP transport.
7
+ // Auth is the customer's Impreza API key + secret, passed in via env
8
+ // (`IMPREZA_API_KEY` / `IMPREZA_API_SECRET`).
9
+ //
10
+ // Iterations:
11
+ // A — list servers/apps/deployments, deploy_custom (3 modes), uninstall.
12
+ // B — logs / restart / change_domain / add_onion /
13
+ // deploy_catalog_app + `setup --tool ...` wizard.
14
+ //
15
+ // Subcommands:
16
+ // (no args) — boot the MCP server over stdio (default)
17
+ // setup --tool <name> — print ready-to-paste AI-tool config snippet
18
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
19
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
20
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
21
+ import { z } from 'zod';
22
+ import { ImprezaClient, tarProjectDir, } from './client.js';
23
+ import { runSetup } from './setup.js';
24
+ // ─────────────────────────────────────────────────────────────────────
25
+ // Subcommand dispatch — `setup` short-circuits before env validation.
26
+ // ─────────────────────────────────────────────────────────────────────
27
+ const sub = process.argv[2];
28
+ if (sub === 'setup') {
29
+ runSetup(process.argv.slice(3));
30
+ // runSetup() calls process.exit; this line never executes.
31
+ }
32
+ if (sub === '--help' || sub === '-h' || sub === 'help') {
33
+ console.log('Usage:');
34
+ console.log(' impreza-mcp Run the MCP server over stdio (default).');
35
+ console.log(' Requires IMPREZA_API_KEY + IMPREZA_API_SECRET env.');
36
+ console.log(' impreza-mcp setup --tool <name> Print a ready-to-paste config snippet.');
37
+ console.log(' Tools: claude-code | cursor | continue | zed | codex-cli');
38
+ console.log(' impreza-mcp --version Print version.');
39
+ process.exit(0);
40
+ }
41
+ if (sub === '--version' || sub === '-V' || sub === 'version') {
42
+ console.log('impreza-mcp 0.1.0');
43
+ process.exit(0);
44
+ }
45
+ // ─────────────────────────────────────────────────────────────────────
46
+ // Env validation
47
+ // ─────────────────────────────────────────────────────────────────────
48
+ const envSchema = z.object({
49
+ IMPREZA_API_KEY: z.string().min(8, 'IMPREZA_API_KEY must be set (starts with imp_)'),
50
+ IMPREZA_API_SECRET: z.string().min(16, 'IMPREZA_API_SECRET must be set'),
51
+ IMPREZA_BASE_URL: z.string().url().default('https://api.imprezahost.com'),
52
+ });
53
+ let cfg;
54
+ try {
55
+ cfg = envSchema.parse(process.env);
56
+ }
57
+ catch (err) {
58
+ // Log to stderr (stdout is the MCP transport stream — must stay clean).
59
+ if (err instanceof z.ZodError) {
60
+ console.error('[impreza-mcp] env validation failed:');
61
+ for (const issue of err.issues) {
62
+ console.error(` - ${issue.path.join('.')}: ${issue.message}`);
63
+ }
64
+ console.error('\nSet IMPREZA_API_KEY + IMPREZA_API_SECRET in your MCP config env (see README).');
65
+ }
66
+ else {
67
+ console.error('[impreza-mcp] env parse error:', err);
68
+ }
69
+ process.exit(2);
70
+ }
71
+ const impreza = new ImprezaClient({
72
+ baseURL: cfg.IMPREZA_BASE_URL,
73
+ apiKey: cfg.IMPREZA_API_KEY,
74
+ apiSecret: cfg.IMPREZA_API_SECRET,
75
+ });
76
+ // ─────────────────────────────────────────────────────────────────────
77
+ // MCP server setup
78
+ // ─────────────────────────────────────────────────────────────────────
79
+ const server = new Server({ name: 'impreza-mcp', version: '0.1.0' }, { capabilities: { tools: {} } });
80
+ // Tool definitions — each one wraps an Impreza REST call. JSON Schema
81
+ // here is what the AI sees in its tool catalog; the description should
82
+ // be rich enough that the LLM picks the right tool without hand-holding.
83
+ const TOOLS = [
84
+ {
85
+ name: 'impreza_list_servers',
86
+ description: 'List every Impreza-managed VPS the customer owns (and any external bring-your-own server they registered). ' +
87
+ 'Use to find the right `agent_id` before calling `impreza_deploy_custom`. ' +
88
+ 'Returns hostname + IP + status (online/offline/draining/revoked) for each.',
89
+ inputSchema: {
90
+ type: 'object',
91
+ properties: {},
92
+ additionalProperties: false,
93
+ },
94
+ },
95
+ {
96
+ name: 'impreza_list_apps',
97
+ description: 'List apps available in the Impreza curated catalog (Vaultwarden, n8n, Nextcloud, etc.). ' +
98
+ 'These are pre-packaged manifests the customer can install with one click. ' +
99
+ 'For non-catalog apps the customer built themselves, use `impreza_deploy_custom` instead.',
100
+ inputSchema: {
101
+ type: 'object',
102
+ properties: {
103
+ search: { type: 'string', description: 'Optional case-insensitive substring filter on name/category/tags.' },
104
+ category: { type: 'string', description: 'Optional category filter (e.g. "media", "productivity").' },
105
+ },
106
+ additionalProperties: false,
107
+ },
108
+ },
109
+ {
110
+ name: 'impreza_list_deployments',
111
+ description: 'List the customer\'s currently-installed app deployments (catalog + custom). ' +
112
+ 'Optionally narrow to a single server via `agent_id`. ' +
113
+ 'Use to confirm what\'s running before adding more, or to find a `deployment_id` to uninstall/restart.',
114
+ inputSchema: {
115
+ type: 'object',
116
+ properties: {
117
+ agent_id: { type: 'string', description: 'Optional: narrow to a single server.' },
118
+ status: { type: 'string', description: 'Optional: filter by status (running, failed, installing, ...).' },
119
+ },
120
+ additionalProperties: false,
121
+ },
122
+ },
123
+ {
124
+ name: 'impreza_deploy_custom',
125
+ description: 'Deploy a custom (non-catalog) app to an Impreza VPS. Three modes — pick exactly one:\n' +
126
+ ' • `mode: "image"` — public Docker image URL (`image: "ghcr.io/user/app:tag"`).\n' +
127
+ ' • `mode: "dockerfile"` — local project directory with a Dockerfile (`dir: "/abs/path/to/project"`). ' +
128
+ 'The MCP server tars + uploads it; the agent runs `docker build` locally on the VPS.\n' +
129
+ ' • `mode: "manifest"` — a full docker-compose manifest object (advanced; same schema as catalog apps).\n' +
130
+ 'Always required: `name`, `agent_id`. Use `impreza_list_servers` to find a valid `agent_id`.\n' +
131
+ 'When the customer says "deploy this" with a project open, Dockerfile mode is the right choice.',
132
+ inputSchema: {
133
+ type: 'object',
134
+ properties: {
135
+ name: { type: 'string', description: 'Per-account-unique deploy name (3-100 chars, [a-z0-9_-]).' },
136
+ agent_id: { type: 'string', description: 'Target VPS agent_id (from impreza_list_servers).' },
137
+ mode: { type: 'string', enum: ['image', 'dockerfile', 'manifest'], description: 'Source mode.' },
138
+ domain: { type: 'string', description: 'Public hostname. Omit when `onion: true` for an onion-only deploy.' },
139
+ onion: { type: 'boolean', description: 'Also publish a Tor v3 hidden service. Default false.' },
140
+ cpus: { type: 'number', description: 'CPU limit (cores; 1.0 = one core). Default 1.0 server-side.' },
141
+ memory_mb: { type: 'number', description: 'Memory limit in MB. Default 512 server-side.' },
142
+ target_port: { type: 'number', description: 'Port the container listens on (default 80).' },
143
+ vars: { type: 'object', description: 'Environment variables to inject into the container.' },
144
+ image: { type: 'string', description: 'Required when mode=image. Public Docker image reference.' },
145
+ dir: { type: 'string', description: 'Required when mode=dockerfile. Absolute path to the project directory.' },
146
+ dockerfile_path: { type: 'string', description: 'Optional Dockerfile path relative to dir (default "Dockerfile").' },
147
+ manifest: { type: 'object', description: 'Required when mode=manifest. Full app manifest object.' },
148
+ },
149
+ required: ['name', 'agent_id', 'mode'],
150
+ additionalProperties: false,
151
+ },
152
+ },
153
+ {
154
+ name: 'impreza_uninstall_deployment',
155
+ description: 'Uninstall a deployment (catalog or custom) by `deployment_id`. ' +
156
+ 'Set `purge_data: true` to also wipe the deployment\'s data volume. ' +
157
+ 'Idempotent — calling on an already-uninstalled deployment is a no-op success.',
158
+ inputSchema: {
159
+ type: 'object',
160
+ properties: {
161
+ deployment_id: { type: 'string', description: 'The dpl_... id to remove.' },
162
+ purge_data: { type: 'boolean', description: 'Wipe the data volume too. Default false.' },
163
+ },
164
+ required: ['deployment_id'],
165
+ additionalProperties: false,
166
+ },
167
+ },
168
+ {
169
+ name: 'impreza_get_logs',
170
+ description: 'Fetch the last N lines of container logs for a deployment. Synchronous — the server enqueues a log-tail command for the agent, then waits up to ~25 seconds for the chunks to come back. Use this to debug a failed deploy (`impreza_list_deployments` showed last_error) or to inspect a running app\'s output.',
171
+ inputSchema: {
172
+ type: 'object',
173
+ properties: {
174
+ deployment_id: { type: 'string', description: 'The dpl_... id to tail.' },
175
+ lines: { type: 'number', description: 'Number of trailing lines (1-5000, default 200).' },
176
+ since_seconds: { type: 'number', description: 'Only logs from the last N seconds. Default 0 = no limit.' },
177
+ },
178
+ required: ['deployment_id'],
179
+ additionalProperties: false,
180
+ },
181
+ },
182
+ {
183
+ name: 'impreza_restart_deployment',
184
+ description: 'Restart a deployment\'s docker-compose stack (non-destructive). The container is stopped + started; data volumes preserved. Status flips to `installing` briefly then back to `running`. Works for both catalog and custom deployments.',
185
+ inputSchema: {
186
+ type: 'object',
187
+ properties: {
188
+ deployment_id: { type: 'string', description: 'The dpl_... id to restart.' },
189
+ },
190
+ required: ['deployment_id'],
191
+ additionalProperties: false,
192
+ },
193
+ },
194
+ {
195
+ name: 'impreza_change_domain',
196
+ description: 'Re-route a RUNNING deployment to a new clearnet hostname without touching its container or data. The agent regenerates its Caddy fragment + reloads zero-downtime; Let\'s Encrypt issues a fresh cert on the first hit. Use to migrate from an auto-subdomain to a custom domain, or vice-versa, or just to rename. Deployment must be in status=running (Phase 9.19).',
197
+ inputSchema: {
198
+ type: 'object',
199
+ properties: {
200
+ deployment_id: { type: 'string', description: 'The dpl_... id to re-route.' },
201
+ domain: { type: 'string', description: 'New clearnet hostname (no scheme). Must differ from the current one.' },
202
+ },
203
+ required: ['deployment_id', 'domain'],
204
+ additionalProperties: false,
205
+ },
206
+ },
207
+ {
208
+ name: 'impreza_add_onion',
209
+ description: 'Add a Tor v3 hidden service (.onion mirror) to a deployment that\'s currently running clearnet-only. The agent provisions Tor + publishes the hidden service alongside the existing clearnet route. Useful when the customer realized post-install that they wanted Tor exposure. The .onion address is persisted on the deployment row. Catalog deployments must declare `supports.onion: true`; for custom deployments this is always supported (Phase 89).',
210
+ inputSchema: {
211
+ type: 'object',
212
+ properties: {
213
+ deployment_id: { type: 'string', description: 'The dpl_... id to extend.' },
214
+ },
215
+ required: ['deployment_id'],
216
+ additionalProperties: false,
217
+ },
218
+ },
219
+ {
220
+ name: 'impreza_deploy_catalog_app',
221
+ description: 'Install an app from the Impreza catalog (Vaultwarden, n8n, Nextcloud, etc.) on a target VPS. Use `impreza_list_apps` to discover available names. Pair with `impreza_list_servers` to find the right `agent_id`. Variables specific to the app (e.g. `signups_allowed` for Vaultwarden) go in `vars`. For non-catalog apps the customer built themselves, use `impreza_deploy_custom` instead.',
222
+ inputSchema: {
223
+ type: 'object',
224
+ properties: {
225
+ app_name: { type: 'string', description: 'Catalog app name (e.g. "vaultwarden").' },
226
+ agent_id: { type: 'string', description: 'Target VPS agent_id.' },
227
+ app_version: { type: 'string', description: 'Optional pinned version. Default: latest published.' },
228
+ domain: { type: 'string', description: 'Public hostname for clearnet TLS. Omit + set onion:true for onion-only.' },
229
+ onion: { type: 'boolean', description: 'Also publish a Tor v3 hidden service mirror.' },
230
+ vars: { type: 'object', description: 'App-specific manifest variables (KEY → value).' },
231
+ },
232
+ required: ['app_name', 'agent_id'],
233
+ additionalProperties: false,
234
+ },
235
+ },
236
+ ];
237
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
238
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
239
+ const { name, arguments: rawArgs } = req.params;
240
+ const args = (rawArgs ?? {});
241
+ try {
242
+ switch (name) {
243
+ case 'impreza_list_servers':
244
+ return toResult(await impreza.get('/v1/platform/servers'));
245
+ case 'impreza_list_apps': {
246
+ const query = {};
247
+ if (typeof args.search === 'string')
248
+ query.search = args.search;
249
+ if (typeof args.category === 'string')
250
+ query.category = args.category;
251
+ return toResult(await impreza.get('/v1/platform/apps', query));
252
+ }
253
+ case 'impreza_list_deployments': {
254
+ const query = {};
255
+ if (typeof args.agent_id === 'string')
256
+ query.agent_id = args.agent_id;
257
+ if (typeof args.status === 'string')
258
+ query.status = args.status;
259
+ const [catalog, custom] = await Promise.all([
260
+ impreza.get('/v1/platform/deployments', query),
261
+ impreza
262
+ .get('/v1/platform/deployments/custom', query)
263
+ // Custom is best-effort — if the endpoint isn't ready on a
264
+ // given control plane, surface catalog only rather than
265
+ // failing the whole tool call.
266
+ .catch(() => ({ deployments: [], total: 0 })),
267
+ ]);
268
+ return toResult({
269
+ deployments: [...catalog.deployments, ...custom.deployments],
270
+ total: catalog.total + custom.total,
271
+ catalog_count: catalog.total,
272
+ custom_count: custom.total,
273
+ });
274
+ }
275
+ case 'impreza_deploy_custom':
276
+ return toResult(await deployCustom(args));
277
+ case 'impreza_uninstall_deployment': {
278
+ const dep = String(args.deployment_id ?? '');
279
+ if (!dep)
280
+ return toError('deployment_id is required');
281
+ const purge = args.purge_data === true;
282
+ const body = { purge_data: purge, confirm: true };
283
+ return toResult(await impreza.post(`/v1/platform/deployments/${encodeURIComponent(dep)}/uninstall`, body));
284
+ }
285
+ case 'impreza_get_logs': {
286
+ const dep = String(args.deployment_id ?? '');
287
+ if (!dep)
288
+ return toError('deployment_id is required');
289
+ const body = {};
290
+ if (typeof args.lines === 'number')
291
+ body.lines = args.lines;
292
+ if (typeof args.since_seconds === 'number')
293
+ body.since_seconds = args.since_seconds;
294
+ return toResult(await impreza.post(`/v1/platform/deployments/${encodeURIComponent(dep)}/logs`, body));
295
+ }
296
+ case 'impreza_restart_deployment': {
297
+ const dep = String(args.deployment_id ?? '');
298
+ if (!dep)
299
+ return toError('deployment_id is required');
300
+ return toResult(await impreza.post(`/v1/platform/deployments/${encodeURIComponent(dep)}/restart`, {}));
301
+ }
302
+ case 'impreza_change_domain': {
303
+ const dep = String(args.deployment_id ?? '');
304
+ const newDomain = String(args.domain ?? '');
305
+ if (!dep)
306
+ return toError('deployment_id is required');
307
+ if (!newDomain)
308
+ return toError('domain is required');
309
+ return toResult(await impreza.post(`/v1/platform/deployments/${encodeURIComponent(dep)}/domain`, { domain: newDomain }));
310
+ }
311
+ case 'impreza_add_onion': {
312
+ const dep = String(args.deployment_id ?? '');
313
+ if (!dep)
314
+ return toError('deployment_id is required');
315
+ return toResult(await impreza.post(`/v1/platform/deployments/${encodeURIComponent(dep)}/onion/add`, {}));
316
+ }
317
+ case 'impreza_deploy_catalog_app': {
318
+ const appName = String(args.app_name ?? '');
319
+ const agentId = String(args.agent_id ?? '');
320
+ if (!appName)
321
+ return toError('app_name is required');
322
+ if (!agentId)
323
+ return toError('agent_id is required');
324
+ const body = { app_name: appName, agent_id: agentId };
325
+ if (typeof args.app_version === 'string')
326
+ body.app_version = args.app_version;
327
+ if (typeof args.domain === 'string')
328
+ body.domain = args.domain;
329
+ if (typeof args.onion === 'boolean')
330
+ body.onion = args.onion;
331
+ if (args.vars && typeof args.vars === 'object')
332
+ body.vars = args.vars;
333
+ return toResult(await impreza.post('/v1/platform/deployments', body));
334
+ }
335
+ default:
336
+ return toError(`unknown tool: ${name}`);
337
+ }
338
+ }
339
+ catch (err) {
340
+ const msg = err instanceof Error ? err.message : String(err);
341
+ return toError(msg);
342
+ }
343
+ });
344
+ async function deployCustom(args) {
345
+ const name = String(args.name ?? '');
346
+ const agentId = String(args.agent_id ?? '');
347
+ const mode = String(args.mode ?? '');
348
+ if (!name || !agentId || !mode) {
349
+ throw new Error('name, agent_id, and mode are required');
350
+ }
351
+ const body = { name, agent_id: agentId, mode };
352
+ if (typeof args.domain === 'string')
353
+ body.domain = args.domain;
354
+ if (typeof args.onion === 'boolean')
355
+ body.onion = args.onion;
356
+ if (typeof args.cpus === 'number')
357
+ body.cpus = args.cpus;
358
+ if (typeof args.memory_mb === 'number')
359
+ body.memory_mb = args.memory_mb;
360
+ if (typeof args.target_port === 'number')
361
+ body.target_port = args.target_port;
362
+ if (args.vars && typeof args.vars === 'object')
363
+ body.vars = args.vars;
364
+ let traceTail = '';
365
+ switch (mode) {
366
+ case 'image':
367
+ if (typeof args.image !== 'string' || !args.image) {
368
+ throw new Error('mode=image requires `image` (public registry reference)');
369
+ }
370
+ body.image = args.image;
371
+ break;
372
+ case 'dockerfile': {
373
+ if (typeof args.dir !== 'string' || !args.dir) {
374
+ throw new Error('mode=dockerfile requires `dir` (absolute path to the project directory)');
375
+ }
376
+ // Tar locally + upload to /custom/contexts → get back context_id.
377
+ const packed = await tarProjectDir(args.dir);
378
+ try {
379
+ const upload = await impreza.postRaw('/v1/platform/deployments/custom/contexts', 'application/gzip', packed.bytes);
380
+ body.context_id = upload.context_id;
381
+ if (typeof args.dockerfile_path === 'string' && args.dockerfile_path && args.dockerfile_path !== 'Dockerfile') {
382
+ body.dockerfile_path = args.dockerfile_path;
383
+ }
384
+ traceTail = ` (uploaded ${packed.sizeBytes} B → ${upload.context_id})`;
385
+ }
386
+ finally {
387
+ await packed.cleanup();
388
+ }
389
+ break;
390
+ }
391
+ case 'manifest':
392
+ if (!args.manifest || typeof args.manifest !== 'object') {
393
+ throw new Error('mode=manifest requires `manifest` (object with runtime.type + runtime.compose_yaml)');
394
+ }
395
+ body.manifest = args.manifest;
396
+ break;
397
+ default:
398
+ throw new Error(`unknown mode "${mode}" (expected image / dockerfile / manifest)`);
399
+ }
400
+ const created = await impreza.post('/v1/platform/deployments/custom', body);
401
+ if (traceTail) {
402
+ return { ...created, _trace: created.id + traceTail };
403
+ }
404
+ return created;
405
+ }
406
+ // ─────────────────────────────────────────────────────────────────────
407
+ // Result shape — MCP wants either content[] or isError + content[]
408
+ // ─────────────────────────────────────────────────────────────────────
409
+ function toResult(payload) {
410
+ return {
411
+ content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],
412
+ };
413
+ }
414
+ function toError(message) {
415
+ return {
416
+ content: [{ type: 'text', text: message }],
417
+ isError: true,
418
+ };
419
+ }
420
+ // ─────────────────────────────────────────────────────────────────────
421
+ // Boot
422
+ // ─────────────────────────────────────────────────────────────────────
423
+ async function main() {
424
+ const transport = new StdioServerTransport();
425
+ await server.connect(transport);
426
+ // Stay alive until stdin closes — the AI tool manages the process
427
+ // lifecycle, we just answer requests on demand.
428
+ }
429
+ main().catch((err) => {
430
+ console.error('[impreza-mcp] fatal:', err);
431
+ process.exit(1);
432
+ });
433
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Run the wizard. Argv passed in is everything AFTER the `setup`
3
+ * subcommand (so `--tool claude-code ...`). Exits the process on
4
+ * completion (zero for success, non-zero on bad input).
5
+ */
6
+ export declare function runSetup(argv: readonly string[]): never;
package/dist/setup.js ADDED
@@ -0,0 +1,215 @@
1
+ // `npx impreza-mcp setup --tool <name>` wizard.
2
+ //
3
+ // Generates the ready-to-paste MCP config snippet for whatever AI tool
4
+ // the customer is configuring, plus the file path they should drop it
5
+ // into and the post-config step (almost always "restart the AI tool").
6
+ //
7
+ // No filesystem mutations. The wizard prints to stdout; the customer
8
+ // pastes manually. This avoids the bad failure mode where we silently
9
+ // corrupt an existing config that already has other MCP servers.
10
+ //
11
+ // Supported tools (`--tool` values):
12
+ //
13
+ // claude-code — Anthropic Claude Desktop / Claude Code
14
+ // cursor — Cursor
15
+ // continue — Continue (VS Code / JetBrains)
16
+ // zed — Zed editor
17
+ // codex-cli — OpenAI Codex CLI
18
+ import { homedir, platform } from 'node:os';
19
+ import { join } from 'node:path';
20
+ const SUPPORTED = ['claude-code', 'cursor', 'continue', 'zed', 'codex-cli'];
21
+ const SERVER_NAME = 'impreza';
22
+ const NPX_COMMAND = 'npx';
23
+ const NPX_ARGS = ['-y', 'impreza-mcp'];
24
+ /**
25
+ * Run the wizard. Argv passed in is everything AFTER the `setup`
26
+ * subcommand (so `--tool claude-code ...`). Exits the process on
27
+ * completion (zero for success, non-zero on bad input).
28
+ */
29
+ export function runSetup(argv) {
30
+ const opts = parseFlags(argv);
31
+ if (opts.help) {
32
+ printHelp();
33
+ process.exit(0);
34
+ }
35
+ const tool = opts.tool;
36
+ if (!tool) {
37
+ console.error('error: --tool is required');
38
+ console.error('');
39
+ printHelp();
40
+ process.exit(2);
41
+ }
42
+ if (!SUPPORTED.includes(tool)) {
43
+ console.error(`error: unknown tool "${tool}"`);
44
+ console.error(`supported: ${SUPPORTED.join(', ')}`);
45
+ process.exit(2);
46
+ }
47
+ const snippet = renderSnippet(tool);
48
+ const path = configPath(tool);
49
+ const restartHint = restartInstruction(tool);
50
+ console.log(`# impreza-mcp setup — ${tool}\n`);
51
+ console.log(`Add the following block to ${path === null ? 'your AI tool\'s MCP config file' : path}:\n`);
52
+ console.log(snippet);
53
+ console.log('');
54
+ console.log('Then:');
55
+ let step = 1;
56
+ if (path === null) {
57
+ console.log(` ${step++}. consult the tool's docs for the exact config file path`);
58
+ }
59
+ console.log(` ${step++}. replace \`imp_...\` / the secret with your real Impreza API key + secret`);
60
+ console.log(" (clientarea → API Keys; whitelist this machine's IP)");
61
+ console.log(` ${step++}. ${restartHint}`);
62
+ console.log('');
63
+ console.log('Verify: ask your AI to run `impreza_list_servers`. It should list your VPSes.');
64
+ process.exit(0);
65
+ }
66
+ function parseFlags(argv) {
67
+ const out = { help: false };
68
+ for (let i = 0; i < argv.length; i++) {
69
+ const a = argv[i];
70
+ if (a === '--help' || a === '-h')
71
+ out.help = true;
72
+ else if (a === '--tool') {
73
+ const next = argv[i + 1];
74
+ if (!next) {
75
+ console.error('error: --tool requires a value');
76
+ process.exit(2);
77
+ }
78
+ out.tool = next;
79
+ i++;
80
+ }
81
+ else if (a?.startsWith('--tool=')) {
82
+ out.tool = a.slice('--tool='.length);
83
+ }
84
+ else {
85
+ console.error(`error: unknown flag "${a}"`);
86
+ process.exit(2);
87
+ }
88
+ }
89
+ return out;
90
+ }
91
+ function printHelp() {
92
+ console.log('Usage: npx impreza-mcp setup --tool <name>');
93
+ console.log('');
94
+ console.log('Supported tools:');
95
+ console.log(' claude-code Anthropic Claude Desktop / Claude Code');
96
+ console.log(' cursor Cursor');
97
+ console.log(' continue Continue (VS Code / JetBrains)');
98
+ console.log(' zed Zed editor');
99
+ console.log(' codex-cli OpenAI Codex CLI');
100
+ console.log('');
101
+ console.log('Example:');
102
+ console.log(' npx impreza-mcp setup --tool claude-code');
103
+ }
104
+ // ─────────────────────────────────────────────────────────────────────
105
+ // Per-tool config snippet generators
106
+ // ─────────────────────────────────────────────────────────────────────
107
+ function renderSnippet(tool) {
108
+ switch (tool) {
109
+ case 'claude-code':
110
+ case 'cursor':
111
+ // Both speak the standard `mcpServers` shape.
112
+ return jsonBlock({
113
+ mcpServers: {
114
+ [SERVER_NAME]: stdioCommand(),
115
+ },
116
+ });
117
+ case 'continue':
118
+ return jsonBlock({
119
+ experimental: {
120
+ modelContextProtocolServers: [
121
+ {
122
+ transport: {
123
+ type: 'stdio',
124
+ command: NPX_COMMAND,
125
+ args: NPX_ARGS,
126
+ env: envBlock(),
127
+ },
128
+ },
129
+ ],
130
+ },
131
+ });
132
+ case 'zed':
133
+ return jsonBlock({
134
+ context_servers: {
135
+ [SERVER_NAME]: {
136
+ command: {
137
+ path: NPX_COMMAND,
138
+ args: NPX_ARGS,
139
+ env: envBlock(),
140
+ },
141
+ },
142
+ },
143
+ });
144
+ case 'codex-cli':
145
+ // Codex CLI's MCP config uses the same `mcpServers` shape as
146
+ // Claude / Cursor, with a slightly different file path. Same
147
+ // JSON snippet — only the destination differs.
148
+ return jsonBlock({
149
+ mcpServers: {
150
+ [SERVER_NAME]: stdioCommand(),
151
+ },
152
+ });
153
+ }
154
+ }
155
+ function stdioCommand() {
156
+ return {
157
+ command: NPX_COMMAND,
158
+ args: NPX_ARGS,
159
+ env: envBlock(),
160
+ };
161
+ }
162
+ function envBlock() {
163
+ return {
164
+ IMPREZA_API_KEY: 'imp_REPLACE_ME',
165
+ IMPREZA_API_SECRET: 'REPLACE_ME',
166
+ };
167
+ }
168
+ function jsonBlock(value) {
169
+ return JSON.stringify(value, null, 2);
170
+ }
171
+ // ─────────────────────────────────────────────────────────────────────
172
+ // Per-tool config-file paths (informational, never written)
173
+ // ─────────────────────────────────────────────────────────────────────
174
+ function configPath(tool) {
175
+ const home = homedir();
176
+ const plat = platform();
177
+ switch (tool) {
178
+ case 'claude-code':
179
+ if (plat === 'darwin')
180
+ return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
181
+ if (plat === 'win32')
182
+ return join(process.env.APPDATA ?? join(home, 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
183
+ return join(home, '.config', 'Claude', 'claude_desktop_config.json');
184
+ case 'cursor':
185
+ return join(home, '.cursor', 'mcp.json');
186
+ case 'continue':
187
+ return join(home, '.continue', 'config.json');
188
+ case 'zed':
189
+ if (plat === 'darwin')
190
+ return join(home, '.config', 'zed', 'settings.json');
191
+ if (plat === 'win32')
192
+ return join(process.env.APPDATA ?? join(home, 'AppData', 'Roaming'), 'Zed', 'settings.json');
193
+ return join(home, '.config', 'zed', 'settings.json');
194
+ case 'codex-cli':
195
+ // Codex CLI's MCP config lives in `~/.codex/config.toml` OR
196
+ // a parallel JSON file depending on version. The customer
197
+ // knows which they have; don't guess.
198
+ return null;
199
+ }
200
+ }
201
+ function restartInstruction(tool) {
202
+ switch (tool) {
203
+ case 'claude-code':
204
+ return 'fully quit + re-open Claude (Cmd/Ctrl+Q, then launch again — reload-on-MCP-config-change isn\'t supported)';
205
+ case 'cursor':
206
+ return 'quit + re-open Cursor (the MCP servers re-launch on startup)';
207
+ case 'continue':
208
+ return 'reload your editor window (VS Code: Cmd/Ctrl+Shift+P → "Developer: Reload Window"; JetBrains: restart)';
209
+ case 'zed':
210
+ return 'quit + re-open Zed';
211
+ case 'codex-cli':
212
+ return 'restart any running codex session (the MCP server attaches per-session)';
213
+ }
214
+ }
215
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "impreza-mcp",
3
+ "version": "0.1.0",
4
+ "description": "Model Context Protocol server for Impreza Host — lets Claude Code / Cursor / Codex / Continue / Zed deploy customer-built apps to managed Impreza VPSes without leaving the chat.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "impreza-mcp": "dist/server.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.json",
17
+ "watch": "tsc -p tsconfig.json --watch",
18
+ "lint": "eslint src",
19
+ "typecheck": "tsc --noEmit",
20
+ "test": "vitest run",
21
+ "prepare": "npm run build"
22
+ },
23
+ "engines": {
24
+ "node": ">=20.0.0"
25
+ },
26
+ "homepage": "https://github.com/imprezahost/impreza-mcp",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/imprezahost/impreza-mcp.git"
30
+ },
31
+ "keywords": [
32
+ "mcp",
33
+ "model-context-protocol",
34
+ "impreza",
35
+ "claude",
36
+ "cursor",
37
+ "deploy",
38
+ "docker",
39
+ "self-hosted"
40
+ ],
41
+ "dependencies": {
42
+ "@modelcontextprotocol/sdk": "^1.0.0",
43
+ "tar": "^7.4.3",
44
+ "zod": "^3.23.8"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^22.10.0",
48
+ "@types/tar": "^6.1.13",
49
+ "@typescript-eslint/eslint-plugin": "^8.18.0",
50
+ "@typescript-eslint/parser": "^8.18.0",
51
+ "eslint": "^9.16.0",
52
+ "typescript": "^5.7.0",
53
+ "vitest": "^2.1.0"
54
+ }
55
+ }