Skip to content

Commit 0e6a39d

Browse files
facundofariasclaude
andcommitted
refactor: Rename environment variables for clarity
Rename environment variables and HTTP headers to be more descriptive: - DEPLOYHQ_USERNAME → DEPLOYHQ_EMAIL - DEPLOYHQ_PASSWORD → DEPLOYHQ_API_KEY - x-deployhq-username → x-deployhq-email - x-deployhq-password → x-deployhq-api-key Updated across: - stdio transport (src/stdio.ts) - HTTP transport handler (src/transports/http-handler.ts) - SSE transport handler (src/transports/sse-handler.ts) - Documentation (README.md, USER_GUIDE.md, CLAUDE.md) - Configuration templates (docs/claude-config.json) - Test scripts (test-stdio.sh) This makes it clearer that the "password" field expects a DeployHQ API key, not the user's password, and that "username" is specifically the email address. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent c77927d commit 0e6a39d

File tree

8 files changed

+206
-44
lines changed

8 files changed

+206
-44
lines changed

CLAUDE.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
DeployHQ MCP Server is a Model Context Protocol (MCP) server that enables AI assistants (Claude Desktop and Claude Code) to interact with DeployHQ deployments. It provides two operational modes:
8+
9+
1. **stdio transport** (primary): npm package for direct use with `npx deployhq-mcp-server`
10+
2. **HTTP/SSE transports** (optional): Express server for hosted deployment
11+
12+
## Development Commands
13+
14+
### Build & Type Checking
15+
```bash
16+
npm run build # Compile TypeScript to dist/
17+
npm run type-check # Type check without emitting files
18+
npm run clean # Remove dist/ directory
19+
```
20+
21+
### Development & Testing
22+
```bash
23+
npm run dev # Watch mode for hosted server (index.ts)
24+
npm run start # Run compiled hosted server
25+
npm run lint # ESLint on src/
26+
```
27+
28+
### Testing stdio Transport Locally
29+
```bash
30+
# Build first
31+
npm run build
32+
33+
# Test with environment variables
34+
DEPLOYHQ_EMAIL="email" DEPLOYHQ_API_KEY="pass" DEPLOYHQ_ACCOUNT="account" node dist/stdio.js
35+
36+
# Or use the test script
37+
export DEPLOYHQ_EMAIL="email"
38+
export DEPLOYHQ_API_KEY="pass"
39+
export DEPLOYHQ_ACCOUNT="account"
40+
./test-stdio.sh
41+
```
42+
43+
### Testing with Claude Desktop
44+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
45+
```json
46+
{
47+
"mcpServers": {
48+
"deployhq-local": {
49+
"command": "node",
50+
"args": ["/absolute/path/to/dist/stdio.js"],
51+
"env": {
52+
"DEPLOYHQ_EMAIL": "email",
53+
"DEPLOYHQ_API_KEY": "pass",
54+
"DEPLOYHQ_ACCOUNT": "account"
55+
}
56+
}
57+
}
58+
}
59+
```
60+
Restart Claude Desktop to test.
61+
62+
## Architecture
63+
64+
### Core Components
65+
66+
**Two Entry Points:**
67+
- `src/stdio.ts``dist/stdio.js` (bin entry, stdio transport for MCP clients)
68+
- `src/index.ts``dist/index.js` (Express server for hosted deployment)
69+
70+
**Shared Core:**
71+
- `src/mcp-server.ts`: Factory function `createMCPServer(username, password, account)` that returns a configured MCP Server instance. Used by both stdio and hosted modes.
72+
- `src/tools.ts`: Defines 6 MCP tools (list_projects, get_project, list_servers, list_deployments, get_deployment, create_deployment) with Zod validation schemas
73+
- `src/api-client.ts`: DeployHQClient class for HTTP Basic Auth API calls to DeployHQ REST API
74+
75+
**Transport Handlers (hosted mode only):**
76+
- `src/transports/sse-handler.ts`: Server-Sent Events transport
77+
- `src/transports/http-handler.ts`: HTTP JSON-RPC transport
78+
79+
### Critical: stdio Transport Logging
80+
81+
**IMPORTANT**: When using stdio transport, stdout is reserved exclusively for JSON-RPC messages. All logging MUST go to stderr.
82+
83+
The `src/utils/logger.ts` uses `console.error()` for all log levels (info, error, debug) to prevent corrupting the JSON-RPC stream. Writing to stdout will cause "Unexpected token" JSON parse errors in Claude Desktop/Code.
84+
85+
**Wrong**: `console.log('[INFO] message')` → breaks stdio
86+
**Correct**: `console.error('[INFO] message')` → works with stdio
87+
88+
### Tool Call Flow
89+
90+
1. MCP client (Claude Desktop/Code) sends JSON-RPC request via stdin
91+
2. `StdioServerTransport` receives and parses request
92+
3. `createMCPServer()` routes to appropriate tool handler in `mcp-server.ts`
93+
4. Tool validates input with Zod schema from `tools.ts`
94+
5. `DeployHQClient` makes HTTP request to DeployHQ API with Basic Auth
95+
6. Response returned as JSON-RPC message via stdout
96+
7. Logs go to stderr throughout (visible in client logs but not in JSON stream)
97+
98+
### Credential Flow
99+
100+
**stdio mode**: Environment variables → `stdio.ts` reads → passes to `createMCPServer()`
101+
**hosted mode**: HTTP headers → transport handler extracts → passes to `createMCPServer()`
102+
103+
Per-request client initialization ensures each API call uses the correct user's credentials.
104+
105+
## Key Technical Decisions
106+
107+
### Why stdio for Primary Use Case
108+
- Simpler than hosted deployment (no infrastructure needed)
109+
- Credentials stay local (environment variables)
110+
- Direct process spawning by MCP clients
111+
- No CORS or authentication complexity
112+
113+
### Why Zod for Validation
114+
All tool inputs use Zod schemas for runtime validation. Schemas defined once in `tools.ts` and used for both:
115+
- TypeScript type inference
116+
- Runtime validation in tool handlers
117+
118+
### Why Separate createMCPServer Factory
119+
The factory function `createMCPServer()` encapsulates all MCP server logic and is transport-agnostic. This allows:
120+
- Same business logic for stdio and hosted modes
121+
- Easy testing (can instantiate server without transport)
122+
- Clean separation of concerns
123+
124+
## Available MCP Tools
125+
126+
1. **list_projects**: Get all projects (no params)
127+
2. **get_project**: Get project details (permalink)
128+
3. **list_servers**: List project servers (project)
129+
4. **list_deployments**: List deployments with pagination (project, page?, server_uuid?)
130+
5. **get_deployment**: Get deployment details (project, uuid)
131+
6. **create_deployment**: Create new deployment (project, parent_identifier, start_revision, end_revision, plus optional params)
132+
133+
All tools require valid DeployHQ credentials and return typed responses matching the DeployHQ API.
134+
135+
## Common Development Patterns
136+
137+
### Adding a New Tool
138+
139+
1. Add Zod schema to `src/tools.ts` (e.g., `export const NewToolSchema = z.object({...})`)
140+
2. Add tool definition to `tools` array in `src/tools.ts`
141+
3. Add case to switch statement in `src/mcp-server.ts` CallToolRequestSchema handler
142+
4. Add corresponding method to `DeployHQClient` in `src/api-client.ts` if needed
143+
5. Import schema in `mcp-server.ts` and use for validation
144+
145+
### Testing Changes
146+
147+
Always rebuild after TypeScript changes:
148+
```bash
149+
npm run build
150+
```
151+
152+
For stdio testing, use absolute path to `dist/stdio.js` in client configs to avoid npx caching issues during development.
153+
154+
## Configuration Files
155+
156+
- `docs/claude-config.json`: Universal config template for both Claude Desktop and Claude Code
157+
- `tsconfig.json`: Targets ES2022, outputs to dist/, includes all src files
158+
- `package.json`: Dual entry points (main for hosted, bin for stdio)
159+
160+
## Important: Node Version
161+
162+
Requires Node.js >=20.0.0 (specified in package.json engines). The stdio transport uses modern Node.js features.

README.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ Add to your `.claude.json` file in your project directory.
9191
"command": "npx",
9292
"args": ["-y", "deployhq-mcp-server"],
9393
"env": {
94-
"DEPLOYHQ_USERNAME": "[email protected]",
95-
"DEPLOYHQ_PASSWORD": "your-password",
94+
"DEPLOYHQ_EMAIL": "[email protected]",
95+
"DEPLOYHQ_API_KEY": "your-password",
9696
"DEPLOYHQ_ACCOUNT": "your-account-name"
9797
}
9898
}
@@ -159,8 +159,8 @@ npm run build
159159
### 4. Test locally with environment variables
160160

161161
```bash
162-
DEPLOYHQ_USERNAME="[email protected]" \
163-
DEPLOYHQ_PASSWORD="your-password" \
162+
DEPLOYHQ_EMAIL="[email protected]" \
163+
DEPLOYHQ_API_KEY="your-password" \
164164
DEPLOYHQ_ACCOUNT="your-account" \
165165
node dist/stdio.js
166166
```
@@ -178,8 +178,8 @@ Configure your local `.claude.json` to use the built version:
178178
"command": "node",
179179
"args": ["/path/to/deployhq-mcp-server/dist/stdio.js"],
180180
"env": {
181-
"DEPLOYHQ_USERNAME": "[email protected]",
182-
"DEPLOYHQ_PASSWORD": "your-password",
181+
"DEPLOYHQ_EMAIL": "[email protected]",
182+
"DEPLOYHQ_API_KEY": "your-password",
183183
"DEPLOYHQ_ACCOUNT": "your-account-name"
184184
}
185185
}
@@ -224,8 +224,8 @@ The server can also be deployed as a hosted service with SSE/HTTP transports. Th
224224
4. **Set environment variables**:
225225
- Go to App Settings → Environment Variables
226226
- Add the following as **encrypted** variables:
227-
- `DEPLOYHQ_USERNAME`
228-
- `DEPLOYHQ_PASSWORD`
227+
- `DEPLOYHQ_EMAIL`
228+
- `DEPLOYHQ_API_KEY`
229229
- `DEPLOYHQ_ACCOUNT`
230230
- Add these as regular variables:
231231
- `NODE_ENV=production`
@@ -319,8 +319,8 @@ Test the SSE endpoint:
319319

320320
```bash
321321
curl -N http://localhost:8080/sse \
322-
-H "X-DeployHQ-Username: your-username" \
323-
-H "X-DeployHQ-Password: your-password" \
322+
-H "X-DeployHQ-Email: your-[email protected]" \
323+
-H "X-DeployHQ-API-Key: your-api-key" \
324324
-H "X-DeployHQ-Account: your-account"
325325
```
326326

@@ -329,8 +329,8 @@ Test the HTTP transport endpoint:
329329
```bash
330330
curl -X POST http://localhost:8080/mcp \
331331
-H "Content-Type: application/json" \
332-
-H "X-DeployHQ-Username: your-username" \
333-
-H "X-DeployHQ-Password: your-password" \
332+
-H "X-DeployHQ-Email: your-[email protected]" \
333+
-H "X-DeployHQ-API-Key: your-api-key" \
334334
-H "X-DeployHQ-Account: your-account" \
335335
-d '{
336336
"jsonrpc": "2.0",

docs/USER_GUIDE.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ Open the configuration file and add the DeployHQ MCP server:
7979
"command": "npx",
8080
"args": ["-y", "deployhq-mcp-server"],
8181
"env": {
82-
"DEPLOYHQ_USERNAME": "[email protected]",
83-
"DEPLOYHQ_PASSWORD": "your-40-character-api-key",
82+
"DEPLOYHQ_EMAIL": "[email protected]",
83+
"DEPLOYHQ_API_KEY": "your-40-character-api-key",
8484
"DEPLOYHQ_ACCOUNT": "your-account-name"
8585
}
8686
}
@@ -105,8 +105,8 @@ If you're developing or testing local changes:
105105
"command": "node",
106106
"args": ["/absolute/path/to/deployhq-mcp-server/dist/stdio.js"],
107107
"env": {
108-
"DEPLOYHQ_USERNAME": "[email protected]",
109-
"DEPLOYHQ_PASSWORD": "your-40-character-api-key",
108+
"DEPLOYHQ_EMAIL": "[email protected]",
109+
"DEPLOYHQ_API_KEY": "your-40-character-api-key",
110110
"DEPLOYHQ_ACCOUNT": "your-account-name"
111111
}
112112
}
@@ -163,17 +163,17 @@ This is the easiest way to configure the MCP server for Claude Code CLI.
163163

164164
```bash
165165
claude mcp add deployhq npx -- -y deployhq-mcp-server \
166-
--env DEPLOYHQ_USERNAME[email protected] \
167-
--env DEPLOYHQ_PASSWORD=your-40-character-api-key \
166+
--env DEPLOYHQ_EMAIL[email protected] \
167+
--env DEPLOYHQ_API_KEY=your-40-character-api-key \
168168
--env DEPLOYHQ_ACCOUNT=your-account-name
169169
```
170170

171171
**Using Local Development Build**:
172172

173173
```bash
174174
claude mcp add deployhq-local node -- /absolute/path/to/deployhq-mcp-server/dist/stdio.js \
175-
--env DEPLOYHQ_USERNAME[email protected] \
176-
--env DEPLOYHQ_PASSWORD=your-40-character-api-key \
175+
--env DEPLOYHQ_EMAIL[email protected] \
176+
--env DEPLOYHQ_API_KEY=your-40-character-api-key \
177177
--env DEPLOYHQ_ACCOUNT=your-account-name
178178
```
179179

@@ -220,8 +220,8 @@ Edit your configuration file and add:
220220
"command": "npx",
221221
"args": ["-y", "deployhq-mcp-server"],
222222
"env": {
223-
"DEPLOYHQ_USERNAME": "[email protected]",
224-
"DEPLOYHQ_PASSWORD": "your-40-character-api-key",
223+
"DEPLOYHQ_EMAIL": "[email protected]",
224+
"DEPLOYHQ_API_KEY": "your-40-character-api-key",
225225
"DEPLOYHQ_ACCOUNT": "your-account-name"
226226
}
227227
}
@@ -246,8 +246,8 @@ If you're developing or testing local changes:
246246
"command": "node",
247247
"args": ["/absolute/path/to/deployhq-mcp-server/dist/stdio.js"],
248248
"env": {
249-
"DEPLOYHQ_USERNAME": "[email protected]",
250-
"DEPLOYHQ_PASSWORD": "your-40-character-api-key",
249+
"DEPLOYHQ_EMAIL": "[email protected]",
250+
"DEPLOYHQ_API_KEY": "your-40-character-api-key",
251251
"DEPLOYHQ_ACCOUNT": "your-account-name"
252252
}
253253
}
@@ -265,7 +265,7 @@ If you're developing or testing local changes:
265265
**Development Workflow**:
266266
- After code changes, run `npm run build` to recompile
267267
- Start a new Claude Code session to load the updated code
268-
- Test with environment variables: `DEPLOYHQ_USERNAME=email DEPLOYHQ_PASSWORD=pass DEPLOYHQ_ACCOUNT=account node dist/stdio.js`
268+
- Test with environment variables: `DEPLOYHQ_EMAIL=email DEPLOYHQ_API_KEY=pass DEPLOYHQ_ACCOUNT=account node dist/stdio.js`
269269

270270
### 2. Managing MCP Servers (CLI Command Approach)
271271

@@ -290,8 +290,8 @@ claude mcp remove deployhq
290290
```bash
291291
claude mcp remove deployhq
292292
claude mcp add deployhq npx -- -y deployhq-mcp-server \
293-
--env DEPLOYHQ_USERNAME[email protected] \
294-
--env DEPLOYHQ_PASSWORD=new-api-key \
293+
--env DEPLOYHQ_EMAIL[email protected] \
294+
--env DEPLOYHQ_API_KEY=new-api-key \
295295
--env DEPLOYHQ_ACCOUNT=new-account
296296
```
297297

@@ -505,7 +505,7 @@ Choose the scope that best fits your needs. For most users, `--scope user` or us
505505
2. For local development: Ensure `src/utils/logger.ts` uses `console.error()` not `console.log()`
506506
3. Rebuild after any code changes: `npm run build`
507507
4. Check Claude Code logs for specific error messages
508-
5. Test stdio directly: `echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | DEPLOYHQ_USERNAME=email DEPLOYHQ_PASSWORD=pass DEPLOYHQ_ACCOUNT=account node dist/stdio.js`
508+
5. Test stdio directly: `echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | DEPLOYHQ_EMAIL=email DEPLOYHQ_API_KEY=pass DEPLOYHQ_ACCOUNT=account node dist/stdio.js`
509509

510510
### Issue: Configuration changes not taking effect
511511

docs/claude-config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"command": "npx",
55
"args": ["-y", "deployhq-mcp-server"],
66
"env": {
7-
"DEPLOYHQ_USERNAME": "[email protected]",
8-
"DEPLOYHQ_PASSWORD": "your-password",
7+
"DEPLOYHQ_EMAIL": "[email protected]",
8+
"DEPLOYHQ_API_KEY": "your-api-key",
99
"DEPLOYHQ_ACCOUNT": "your-account-name"
1010
}
1111
}

src/stdio.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@ import { log } from './utils/logger.js';
1515
async function main(): Promise<void> {
1616
try {
1717
// Read credentials from environment variables
18-
const username = process.env.DEPLOYHQ_USERNAME;
19-
const password = process.env.DEPLOYHQ_PASSWORD;
18+
const email = process.env.DEPLOYHQ_EMAIL;
19+
const apiKey = process.env.DEPLOYHQ_API_KEY;
2020
const account = process.env.DEPLOYHQ_ACCOUNT;
2121

2222
// Validate required environment variables
23-
if (!username || !password || !account) {
23+
if (!email || !apiKey || !account) {
2424
log.error('Missing required environment variables');
25-
log.error('Please set: DEPLOYHQ_USERNAME, DEPLOYHQ_PASSWORD, DEPLOYHQ_ACCOUNT');
25+
log.error('Please set: DEPLOYHQ_EMAIL, DEPLOYHQ_API_KEY, DEPLOYHQ_ACCOUNT');
2626
process.exit(1);
2727
}
2828

2929
log.info('Starting DeployHQ MCP Server in stdio mode');
30-
log.debug(`Account: ${account}, Username: ${username}`);
30+
log.debug(`Account: ${account}, Email: ${email}`);
3131

3232
// Create MCP server with user credentials
33-
const server = createMCPServer(username, password, account);
33+
const server = createMCPServer(email, apiKey, account);
3434

3535
// Create stdio transport
3636
const transport = new StdioServerTransport();

src/transports/http-handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ export function setupHTTPRoutes(app: Express): void {
2525
log.info('New HTTP transport request');
2626

2727
// Extract credentials from custom headers
28-
const username = req.headers['x-deployhq-username'] as string || process.env.DEPLOYHQ_USERNAME;
29-
const password = req.headers['x-deployhq-password'] as string || process.env.DEPLOYHQ_PASSWORD;
28+
const username = req.headers['x-deployhq-email'] as string || process.env.DEPLOYHQ_EMAIL;
29+
const password = req.headers['x-deployhq-api-key'] as string || process.env.DEPLOYHQ_API_KEY;
3030
const account = req.headers['x-deployhq-account'] as string || process.env.DEPLOYHQ_ACCOUNT;
3131

3232
// Validate credentials

src/transports/sse-handler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ export function setupSSERoutes(app: Express): void {
2020
log.info('New SSE connection');
2121

2222
// Extract credentials from custom headers
23-
const username = req.headers['x-deployhq-username'] as string || process.env.DEPLOYHQ_USERNAME;
24-
const password = req.headers['x-deployhq-password'] as string || process.env.DEPLOYHQ_PASSWORD;
23+
const username = req.headers['x-deployhq-email'] as string || process.env.DEPLOYHQ_EMAIL;
24+
const password = req.headers['x-deployhq-api-key'] as string || process.env.DEPLOYHQ_API_KEY;
2525
const account = req.headers['x-deployhq-account'] as string || process.env.DEPLOYHQ_ACCOUNT;
2626

2727
// Validate credentials
2828
if (!username || !password || !account) {
2929
log.error('Missing credentials in request headers');
3030
res.status(401).json({
3131
error: 'Unauthorized',
32-
message: 'Missing required headers: X-DeployHQ-Username, X-DeployHQ-Password, X-DeployHQ-Account',
32+
message: 'Missing required headers: X-DeployHQ-Email, X-DeployHQ-API-Key, X-DeployHQ-Account',
3333
});
3434
return;
3535
}

0 commit comments

Comments
 (0)