Skip to content

Commit e9507cc

Browse files
feat: improve MCP server installation (#461)
* feat: improve MCP server installation * fix: update yarn.lock * fix: error handling * fix: switch to path.resolve() * chore: refactor and cleanup error handling code * chore: address PR comments
1 parent 9e83d11 commit e9507cc

10 files changed

Lines changed: 375 additions & 50 deletions

File tree

README.md

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ The CLI can be customized in several ways using command-line args or by creating
2222
* [Usage](#usage)
2323
* [Command Topics](#command-topics)
2424
* [MCP Server for AI Assistants](#mcp-server-for-ai-assistants)
25+
* [This installs both 'dvc' CLI and 'dvc-mcp' server](#this-installs-both-dvc-cli-and-dvc-mcp-server)
26+
* [Access via: npx dvc-mcp](#access-via-npx-dvc-mcp)
2527
* [Repo Configuration](#repo-configuration)
2628
<!-- tocstop -->
2729
# Setup
@@ -149,7 +151,27 @@ USAGE
149151

150152
The DevCycle CLI includes an MCP (Model Context Protocol) server that enables AI coding assistants like Cursor and Claude to manage feature flags directly. This allows you to create, update, and manage feature flags without leaving your coding environment.
151153

152-
## Quick Setup
154+
## Installation
155+
156+
### Option 1: Global Installation (Recommended)
157+
```bash
158+
npm install -g @devcycle/cli
159+
# This installs both 'dvc' CLI and 'dvc-mcp' server
160+
```
161+
162+
### Option 2: Project-Specific Installation
163+
```bash
164+
npm install --save-dev @devcycle/cli
165+
# Access via: npx dvc-mcp
166+
```
167+
168+
### Verify Installation
169+
```bash
170+
dvc-mcp --version # Should display the DevCycle CLI version
171+
dvc --version # Verify CLI is also installed
172+
```
173+
174+
## Configuration
153175

154176
### For Cursor
155177
Add to `.cursor/mcp_settings.json`:
@@ -165,6 +187,10 @@ Add to `.cursor/mcp_settings.json`:
165187

166188
### For Claude Desktop
167189
Add to your Claude configuration file:
190+
191+
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
192+
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
193+
168194
```json
169195
{
170196
"mcpServers": {
@@ -175,9 +201,48 @@ Add to your Claude configuration file:
175201
}
176202
```
177203

178-
The MCP server uses the same authentication as the CLI. Simply run `dvc login sso` first, then your AI assistant can manage feature flags on your behalf.
204+
### For Project-Specific Installation
205+
If you installed locally, update the command path:
206+
```json
207+
{
208+
"mcpServers": {
209+
"devcycle": {
210+
"command": "npx",
211+
"args": ["dvc-mcp"]
212+
}
213+
}
214+
}
215+
```
216+
217+
## Authentication
218+
219+
The MCP server uses the same authentication as the CLI:
220+
221+
1. **Authenticate with DevCycle:**
222+
```bash
223+
dvc login sso
224+
```
225+
226+
2. **Select your project:**
227+
```bash
228+
dvc projects select
229+
```
230+
231+
3. **Verify setup:**
232+
```bash
233+
dvc status
234+
```
235+
236+
Your AI assistant can now manage feature flags on your behalf.
237+
238+
## Troubleshooting
239+
240+
- **Command not found:** Ensure the CLI is installed globally or use `npx dvc-mcp`
241+
- **Authentication errors:** Run `dvc login sso` to re-authenticate
242+
- **No project selected:** Run `dvc projects select` to choose a project
243+
- **Permission issues:** On Unix systems, you may need to restart your terminal after global installation
179244

180-
For detailed documentation, see [docs/mcp.md](docs/mcp.md).
245+
For detailed documentation and advanced usage, see [docs/mcp.md](docs/mcp.md).
181246

182247
# Repo Configuration
183248
The following commands can only be run from the root of a configured repository

bin/mcp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env node
2+
3+
const path = require('path')
4+
5+
// Run the MCP server directly
6+
require(path.resolve(__dirname, '..', 'dist', 'mcp', 'index.js'))

bin/mcp.cmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@echo off
2+
3+
node "%~dp0\mcp" %*

oclif.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "5.21.0",
2+
"version": "5.21.1",
33
"commands": {
44
"authCommand": {
55
"id": "authCommand",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"author": "support@devcycle.com",
66
"bin": {
77
"dvc": "./bin/run",
8-
"dvc-mcp": "./dist/mcp/index.js"
8+
"dvc-mcp": "./bin/mcp"
99
},
1010
"homepage": "https://github.com/DevCycleHQ/cli",
1111
"license": "MIT",

src/api/zodClient.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,12 @@ const UpdateAudienceDto = z
314314
})
315315
.partial()
316316
const VariableValidationEntity = z.object({
317-
schemaType: z.object({}).partial(),
318-
enumValues: z.object({}).partial().optional(),
317+
schemaType: z.string(),
318+
enumValues: z.array(z.string()).optional(),
319319
regexPattern: z.string().optional(),
320320
jsonSchema: z.string().optional(),
321321
description: z.string(),
322-
exampleValue: z.object({}).partial(),
322+
exampleValue: z.any(),
323323
})
324324
const CreateVariableDto = z.object({
325325
name: z.string().max(100).optional(),

src/mcp/index.ts

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,53 @@
33
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
44
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
55
import { DevCycleMCPServer } from './server'
6+
import { readFileSync } from 'fs'
7+
import { join } from 'path'
8+
9+
// Get version for MCP server
10+
function getVersion(): string {
11+
try {
12+
const packagePath = join(__dirname, '..', '..', 'package.json')
13+
const packageJson = JSON.parse(readFileSync(packagePath, 'utf8'))
14+
return packageJson.version
15+
} catch (error) {
16+
return 'unknown version'
17+
}
18+
}
19+
20+
// Handle command line arguments
21+
const args = process.argv.slice(2)
22+
if (args.includes('--version') || args.includes('-v')) {
23+
console.log(getVersion())
24+
process.exit(0)
25+
}
26+
27+
if (args.includes('--help') || args.includes('-h')) {
28+
console.log('DevCycle MCP Server')
29+
console.log('')
30+
console.log(
31+
'A Model Context Protocol server for DevCycle feature flag management.',
32+
)
33+
console.log(
34+
'Designed to be used with AI coding assistants like Cursor and Claude.',
35+
)
36+
console.log('')
37+
console.log('Usage:')
38+
console.log(' dvc-mcp Start the MCP server')
39+
console.log(' dvc-mcp --version Show version information')
40+
console.log(' dvc-mcp --help Show this help message')
41+
console.log('')
42+
console.log(
43+
'For setup instructions, see: https://github.com/DevCycleHQ/cli#mcp-server-for-ai-assistants',
44+
)
45+
process.exit(0)
46+
}
647

748
async function main() {
849
const server = new Server(
950
{
1051
name: 'devcycle',
11-
version: '0.0.1',
52+
version: getVersion(),
1253
},
1354
{
1455
capabilities: {
@@ -27,6 +68,52 @@ async function main() {
2768
}
2869

2970
main().catch((error) => {
30-
console.error('Failed to start DevCycle MCP server:', error)
71+
console.error('❌ Failed to start DevCycle MCP server')
72+
console.error('')
73+
74+
if (error instanceof Error) {
75+
// Check for common error patterns and provide helpful guidance
76+
if (
77+
error.message.includes('authentication') ||
78+
error.message.includes('DEVCYCLE_CLIENT_ID')
79+
) {
80+
console.error('🔐 Authentication Error:')
81+
console.error(` ${error.message}`)
82+
console.error('')
83+
console.error('💡 To fix this:')
84+
console.error(' 1. Run: dvc login sso')
85+
console.error(' 2. Or set environment variables:')
86+
console.error(' export DEVCYCLE_CLIENT_ID="your-client-id"')
87+
console.error(
88+
' export DEVCYCLE_CLIENT_SECRET="your-client-secret"',
89+
)
90+
} else if (
91+
error.message.includes('project') ||
92+
error.message.includes('DEVCYCLE_PROJECT_KEY')
93+
) {
94+
console.error('📁 Project Configuration Error:')
95+
console.error(` ${error.message}`)
96+
console.error('')
97+
console.error('💡 To fix this:')
98+
console.error(' 1. Run: dvc projects select')
99+
console.error(' 2. Or set environment variable:')
100+
console.error(
101+
' export DEVCYCLE_PROJECT_KEY="your-project-key"',
102+
)
103+
} else {
104+
console.error('⚠️ Unexpected Error:')
105+
console.error(` ${error.message}`)
106+
console.error('')
107+
console.error('💡 For help:')
108+
console.error(' - Run: dvc status')
109+
console.error(' - Check: https://docs.devcycle.com')
110+
console.error(' - Contact: support@devcycle.com')
111+
}
112+
} else {
113+
console.error('⚠️ Unknown error occurred')
114+
console.error(` ${error}`)
115+
}
116+
117+
console.error('')
31118
process.exit(1)
32119
})

0 commit comments

Comments
 (0)