iflow-mcp_davidpiazza-cdp_mcp 1.0.0__tar.gz

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.
@@ -0,0 +1,16 @@
1
+ [2026-02-05] [SUCCESS] 步骤1:获取项目 - Fork并克隆项目成功
2
+ 项目URL: https://github.com/DavidPiazza/CDP_MCP
3
+ Fork URL: https://github.com/iflow-mcp/davidpiazza-cdp_mcp
4
+ 包名: davidpiazza-cdp_mcp
5
+ [2026-02-05] [SUCCESS] 步骤2:阅读代码 - 深度阅读理解代码以及相关文档
6
+ - 项目类型:Python MCP服务端项目
7
+ - 使用FastMCP框架
8
+ - 项目未过期
9
+ - 语言:python
10
+ - 包名:iflow-mcp_davidpiazza-cdp_mcp
11
+ [2026-02-05] [SUCCESS] 步骤3:本地测试 - 修改配置文件、构建并本地测试
12
+ - 构建成功
13
+ - 本地测试成功
14
+ - 环境变量:CDP_PATH=/tmp/cdp_test
15
+ - 工具数量:6个
16
+ - 工具列表:list_cdp_programs, get_cdp_usage, execute_cdp, create_data_file, analyze_sound, prepare_spectral
@@ -0,0 +1,604 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ CDP MCP Server v7 - Ultra-Rigid Workflow
4
+ Direct CDP usage exposure with zero interpretation
5
+ Now with 4 core tools including data file creation
6
+ """
7
+
8
+ import os
9
+ import subprocess
10
+ import tempfile
11
+ import platform
12
+ from pathlib import Path
13
+ from typing import List, Dict, Any, Optional, Tuple
14
+ import soundfile as sf
15
+ import numpy as np
16
+
17
+ from mcp.server.fastmcp import FastMCP
18
+
19
+ # Initialize MCP server
20
+ mcp = FastMCP("CDP Sound Transformer v7")
21
+
22
+ # Configuration
23
+ CDP_PATH = os.environ.get("CDP_PATH", "/Users/davidpiazza/cdpr8/_cdp/_cdprogs")
24
+ TEMP_DIR = Path(tempfile.gettempdir()) / "cdp_mcp"
25
+ TEMP_DIR.mkdir(exist_ok=True)
26
+
27
+ # Detect if we're on Apple Silicon
28
+ IS_APPLE_SILICON = platform.machine() == "arm64" and platform.system() == "Darwin"
29
+
30
+ # CDP program categories for organization
31
+ CDP_CATEGORIES = {
32
+ "Spectral Processing": [
33
+ "blur", "clean", "combine", "cross", "focus", "formants",
34
+ "gate", "get", "hilite", "morph", "pitch", "spec", "strange", "stretch"
35
+ ],
36
+ "Time Domain": [
37
+ "modify", "distort", "envel", "extend", "filter", "grain",
38
+ "sfedit", "zigzag"
39
+ ],
40
+ "Synthesis": [
41
+ "synth", "texture", "fracture"
42
+ ],
43
+ "Analysis and Utility": [
44
+ "pvoc", "sndinfo", "housekeep", "submix", "mchshred"
45
+ ],
46
+ "Other": [] # For any programs not categorized
47
+ }
48
+
49
+ # ===== HELPER FUNCTIONS =====
50
+
51
+ def scan_cdp_programs() -> Dict[str, List[str]]:
52
+ """Scan CDP installation directory for available programs"""
53
+ cdp_dir = Path(CDP_PATH)
54
+ if not cdp_dir.exists():
55
+ return {"error": [f"CDP directory not found: {CDP_PATH}"]}
56
+
57
+ # Get all executable files
58
+ programs = []
59
+ try:
60
+ for file in cdp_dir.iterdir():
61
+ if file.is_file() and os.access(file, os.X_OK):
62
+ # Skip obvious non-CDP files
63
+ name = file.name
64
+ if not name.startswith('.') and not name.endswith('.txt'):
65
+ programs.append(name)
66
+ except Exception as e:
67
+ return {"error": [f"Failed to scan CDP directory: {str(e)}"]}
68
+
69
+ # Categorize programs
70
+ categorized = {cat: [] for cat in CDP_CATEGORIES}
71
+ uncategorized = []
72
+
73
+ for prog in sorted(programs):
74
+ categorized_flag = False
75
+ for category, prog_list in CDP_CATEGORIES.items():
76
+ if prog in prog_list:
77
+ categorized[category].append(prog)
78
+ categorized_flag = True
79
+ break
80
+ if not categorized_flag:
81
+ uncategorized.append(prog)
82
+
83
+ # Add uncategorized to "Other"
84
+ if uncategorized:
85
+ categorized["Other"] = uncategorized
86
+
87
+ # Remove empty categories
88
+ categorized = {k: v for k, v in categorized.items() if v}
89
+
90
+ return categorized
91
+
92
+ def run_cdp_for_usage(program: str, subprogram: Optional[str] = None) -> Tuple[int, str, str]:
93
+ """Run CDP program without arguments to get usage information"""
94
+ cmd_path = Path(CDP_PATH) / program
95
+ if not cmd_path.exists():
96
+ return -1, "", f"Program '{program}' not found at {cmd_path}"
97
+
98
+ # Build command - just program and optional subprogram
99
+ args = []
100
+ if subprogram:
101
+ args.append(subprogram)
102
+
103
+ # Build command with architecture prefix if needed
104
+ if IS_APPLE_SILICON:
105
+ cmd = ["arch", "-x86_64", str(cmd_path)] + args
106
+ else:
107
+ cmd = [str(cmd_path)] + args
108
+
109
+ try:
110
+ # Run with no input, expecting usage output
111
+ result = subprocess.run(
112
+ cmd,
113
+ capture_output=True,
114
+ text=True,
115
+ timeout=5 # Prevent hanging
116
+ )
117
+
118
+ # CDP typically outputs usage to stdout or stderr
119
+ # Exit code 255 is normal for usage display
120
+ output = result.stdout if result.stdout else result.stderr
121
+
122
+ return result.returncode, output, result.stderr
123
+
124
+ except subprocess.TimeoutExpired:
125
+ return -1, "", "Command timed out - program may be waiting for input"
126
+ except Exception as e:
127
+ return -1, "", f"Failed to execute: {str(e)}"
128
+
129
+ def run_cdp_command(command: List[str]) -> Tuple[int, str, str]:
130
+ """Execute a CDP command given as array"""
131
+ if not command:
132
+ return -1, "", "Empty command array"
133
+
134
+ program = command[0]
135
+ cmd_path = Path(CDP_PATH) / program
136
+
137
+ if not cmd_path.exists():
138
+ return -1, "", f"Program '{program}' not found at {cmd_path}"
139
+
140
+ # Build full command with architecture prefix if needed
141
+ if IS_APPLE_SILICON:
142
+ full_cmd = ["arch", "-x86_64", str(cmd_path)] + command[1:]
143
+ else:
144
+ full_cmd = [str(cmd_path)] + command[1:]
145
+
146
+ # Log for debugging
147
+ import sys
148
+ print(f"Executing: {' '.join(full_cmd)}", file=sys.stderr)
149
+
150
+ try:
151
+ result = subprocess.run(
152
+ full_cmd,
153
+ capture_output=True,
154
+ text=True,
155
+ cwd=TEMP_DIR # Use temp dir as working directory
156
+ )
157
+
158
+ return result.returncode, result.stdout, result.stderr
159
+
160
+ except Exception as e:
161
+ return -1, "", f"Execution failed: {str(e)}"
162
+
163
+ def get_sound_info(filepath: str) -> Dict[str, Any]:
164
+ """Get basic information about a sound file"""
165
+ try:
166
+ info = sf.info(filepath)
167
+ data, _ = sf.read(filepath)
168
+
169
+ return {
170
+ "duration": info.duration,
171
+ "sample_rate": info.samplerate,
172
+ "channels": info.channels,
173
+ "peak_amplitude": float(np.max(np.abs(data))),
174
+ "format": info.format,
175
+ "frames": info.frames
176
+ }
177
+ except Exception as e:
178
+ return {"error": str(e)}
179
+
180
+ # ===== CORE MCP TOOLS =====
181
+
182
+ @mcp.tool()
183
+ def list_cdp_programs() -> Dict[str, List[str]]:
184
+ """
185
+ List all available CDP programs organized by category.
186
+
187
+ Returns:
188
+ Dictionary with categories as keys and program lists as values
189
+
190
+ Example response:
191
+ {
192
+ "Spectral Processing": ["blur", "focus", "morph", ...],
193
+ "Time Domain": ["modify", "distort", "envel", ...],
194
+ "Synthesis": ["synth", "texture"],
195
+ "Analysis and Utility": ["pvoc", "housekeep", ...]
196
+ }
197
+ """
198
+ return scan_cdp_programs()
199
+
200
+ @mcp.tool()
201
+ def get_cdp_usage(
202
+ program: str,
203
+ subprogram: Optional[str] = None
204
+ ) -> Dict[str, str]:
205
+ """
206
+ Get usage information for a CDP program by running it without arguments.
207
+ This returns the raw usage text directly from CDP.
208
+
209
+ Args:
210
+ program: CDP program name (e.g., 'blur', 'modify')
211
+ subprogram: Optional subprogram (e.g., 'brassage' for modify)
212
+
213
+ Returns:
214
+ Dictionary with usage text and program info
215
+
216
+ Example:
217
+ get_cdp_usage('blur')
218
+ # Returns the full blur usage text showing all modes and parameters
219
+
220
+ get_cdp_usage('modify', 'brassage')
221
+ # Returns usage for modify brassage specifically
222
+ """
223
+ exit_code, output, stderr = run_cdp_for_usage(program, subprogram)
224
+
225
+ # Build response
226
+ response = {
227
+ "program": program,
228
+ "subprogram": subprogram or "none",
229
+ "usage_text": output if output else stderr,
230
+ "exit_code": exit_code
231
+ }
232
+
233
+ # Add hints based on common patterns
234
+ if output or stderr:
235
+ text = output if output else stderr
236
+
237
+ # Check for common indicators
238
+ if "USAGE:" in text or "Usage:" in text:
239
+ response["has_usage"] = True
240
+
241
+ if "MODES:" in text or "Modes:" in text:
242
+ response["has_modes"] = True
243
+
244
+ if any(flag in text for flag in ["-", "FLAGS:", "Options:"]):
245
+ response["has_flags"] = True
246
+
247
+ # Check for double syntax
248
+ if f"{program} {program}" in text.lower():
249
+ response["note"] = f"This program uses double syntax: {program} {program}"
250
+
251
+ return response
252
+
253
+ @mcp.tool()
254
+ def execute_cdp(command: List[str]) -> Dict[str, Any]:
255
+ """
256
+ Execute a CDP command given as an array of strings.
257
+ This is direct execution with no interpretation.
258
+
259
+ Args:
260
+ command: Complete command as array (e.g., ["blur", "blur", "in.ana", "out.ana", "50"])
261
+
262
+ Returns:
263
+ Execution result with status, output, and errors
264
+
265
+ Examples:
266
+ execute_cdp(["blur", "blur", "input.ana", "output.ana", "50"])
267
+ execute_cdp(["modify", "speed", "1", "input.wav", "output.wav", "2.0"])
268
+ execute_cdp(["housekeep", "chans", "4", "stereo.wav", "mono.wav"])
269
+ """
270
+ if not command:
271
+ return {
272
+ "status": "failed",
273
+ "error": "Empty command array provided"
274
+ }
275
+
276
+ # Execute the command
277
+ exit_code, stdout, stderr = run_cdp_command(command)
278
+
279
+ # Determine success
280
+ # CDP often returns non-zero codes even on success
281
+ success = (
282
+ exit_code == 0 or
283
+ (exit_code == 1 and stdout and not stderr) or
284
+ (len(command) > 2 and Path(command[-1]).exists()) # Output file created
285
+ )
286
+
287
+ result = {
288
+ "status": "success" if success else "failed",
289
+ "exit_code": exit_code,
290
+ "command": " ".join(command),
291
+ "stdout": stdout if stdout else "",
292
+ "stderr": stderr if stderr else ""
293
+ }
294
+
295
+ # Add output file info if it appears to be a file operation
296
+ if len(command) > 2:
297
+ possible_output = command[-1]
298
+ if not possible_output.startswith('-') and '.' in possible_output:
299
+ result["output_file"] = possible_output
300
+ if Path(possible_output).exists():
301
+ result["output_exists"] = True
302
+
303
+ return result
304
+
305
+ @mcp.tool()
306
+ def create_data_file(
307
+ filepath: str,
308
+ content: str
309
+ ) -> Dict[str, Any]:
310
+ """
311
+ Create a data file for CDP programs that require them.
312
+ Data files are text files containing parameters specific to each CDP program.
313
+
314
+ Args:
315
+ filepath: Output path for the data file (should end in .txt)
316
+ content: The exact text content to write to the file
317
+
318
+ Returns:
319
+ Dictionary with creation status and file path
320
+
321
+ Examples:
322
+ # For tesselate - two lines with repeat counts and delays
323
+ create_data_file("tess_data.txt", "5 5 5 5\\n0.0 0.1 0.2 0.3")
324
+
325
+ # For texture - note data with MIDI pitches and timing
326
+ create_data_file("texture_notes.txt", "0.0 60 0.5 100\\n0.5 64 0.5 100")
327
+
328
+ # For extend repetitions - times file
329
+ create_data_file("times.txt", "0.0\\n1.5\\n3.2\\n4.8")
330
+ """
331
+ try:
332
+ # Ensure filepath is absolute or relative to temp dir
333
+ if not os.path.isabs(filepath):
334
+ filepath = str(TEMP_DIR / filepath)
335
+
336
+ # Write the content
337
+ Path(filepath).write_text(content)
338
+
339
+ # Verify it was created
340
+ if Path(filepath).exists():
341
+ lines = content.strip().split('\n')
342
+ return {
343
+ "status": "success",
344
+ "filepath": filepath,
345
+ "lines": len(lines),
346
+ "size": len(content),
347
+ "preview": content[:200] + "..." if len(content) > 200 else content
348
+ }
349
+ else:
350
+ return {
351
+ "status": "failed",
352
+ "error": "File was not created"
353
+ }
354
+
355
+ except Exception as e:
356
+ return {
357
+ "status": "failed",
358
+ "error": f"Failed to create data file: {str(e)}"
359
+ }
360
+
361
+ @mcp.tool()
362
+ def analyze_sound(filepath: str) -> Dict[str, Any]:
363
+ """
364
+ Analyze a sound file and return its properties.
365
+
366
+ Args:
367
+ filepath: Path to the sound file
368
+
369
+ Returns:
370
+ Dictionary with duration, sample_rate, channels, peak_amplitude, etc.
371
+ """
372
+ if not Path(filepath).exists():
373
+ return {"error": f"File not found: {filepath}"}
374
+
375
+ return get_sound_info(filepath)
376
+
377
+ @mcp.tool()
378
+ def prepare_spectral(
379
+ input_file: str,
380
+ output_file: str,
381
+ window_size: int = 2048
382
+ ) -> Dict[str, Any]:
383
+ """
384
+ Helper to prepare spectral file using PVOC analysis.
385
+ This is a convenience wrapper around execute_cdp.
386
+
387
+ Args:
388
+ input_file: Input audio file path
389
+ output_file: Output analysis file path (.ana)
390
+ window_size: FFT window size (powers of 2: 64-8192)
391
+
392
+ Returns:
393
+ Result of PVOC analysis execution
394
+ """
395
+ # Check if input is already spectral
396
+ if input_file.endswith('.ana'):
397
+ return {
398
+ "status": "info",
399
+ "message": "Input is already a spectral file",
400
+ "ana_file": input_file
401
+ }
402
+
403
+ # Check input file
404
+ if not Path(input_file).exists():
405
+ return {
406
+ "status": "failed",
407
+ "error": f"Input file not found: {input_file}"
408
+ }
409
+
410
+ # Build PVOC command
411
+ command = [
412
+ "pvoc", "anal", "1",
413
+ input_file,
414
+ output_file,
415
+ f"-c{window_size}"
416
+ ]
417
+
418
+ # Execute
419
+ result = execute_cdp(command)
420
+
421
+ if result["status"] == "success":
422
+ result["ana_file"] = output_file
423
+
424
+ return result
425
+
426
+ # ===== RESOURCES =====
427
+
428
+ @mcp.resource("cdp://workflow")
429
+ def workflow_guide() -> str:
430
+ """CDP v7 Workflow - Ultra-rigid approach"""
431
+ return """# CDP MCP v7 - Ultra-Rigid Workflow
432
+
433
+ ## The Core Process
434
+
435
+ ### 1. List Available Programs
436
+ ```python
437
+ programs = list_cdp_programs()
438
+ # Returns categorized list of all CDP programs
439
+ ```
440
+
441
+ ### 2. Get Usage for Selected Program
442
+ ```python
443
+ usage = get_cdp_usage('blur')
444
+ # Returns exact CDP usage text - no interpretation!
445
+ ```
446
+
447
+ ### 3. Create Data Files if Needed
448
+ ```python
449
+ # When usage mentions DATAFILE, create one:
450
+ create_data_file('data.txt', '5 5 5 5\\n0.0 0.1 0.2 0.3')
451
+ ```
452
+
453
+ ### 4. Execute Exact Command
454
+ ```python
455
+ result = execute_cdp(['blur', 'blur', 'input.ana', 'output.ana', '50'])
456
+ # Direct execution of command array
457
+ ```
458
+
459
+ ## Why This Works
460
+
461
+ 1. **No Parsing** - We don't interpret CDP's output
462
+ 2. **No Guessing** - You see exactly what CDP shows
463
+ 3. **Full Control** - You build the exact command array
464
+ 4. **Simple Server** - Just four core tools, minimal code
465
+
466
+ ## Example Workflow
467
+
468
+ ```python
469
+ # User wants to blur a spectrum
470
+ # Step 1: Find blur program
471
+ programs = list_cdp_programs()
472
+ # See 'blur' in "Spectral Processing" category
473
+
474
+ # Step 2: Get blur usage
475
+ usage = get_cdp_usage('blur')
476
+ # Read CDP's exact usage text showing:
477
+ # "blur blur infile outfile blur"
478
+
479
+ # Step 3: Execute
480
+ result = execute_cdp(['blur', 'blur', 'input.ana', 'output.ana', '20'])
481
+ ```
482
+
483
+ ## Tips
484
+
485
+ - Always check usage before executing
486
+ - CDP exit codes can be non-zero even on success
487
+ - Check if output file exists to verify success
488
+ - Use exact command arrays - no interpretation
489
+
490
+ ## Common Patterns
491
+
492
+ ### Simple command:
493
+ ```python
494
+ execute_cdp(['program', 'mode', 'infile', 'outfile', 'params...'])
495
+ ```
496
+
497
+ ### Compound program:
498
+ ```python
499
+ execute_cdp(['program', 'subprogram', 'mode', 'infile', 'outfile', 'params...'])
500
+ ```
501
+
502
+ ### With flags:
503
+ ```python
504
+ execute_cdp(['program', 'mode', 'infile', 'outfile', '-flag', 'value'])
505
+ ```
506
+ """
507
+
508
+ @mcp.resource("cdp://quickstart")
509
+ def quickstart_examples() -> str:
510
+ """Quick examples for common CDP operations"""
511
+ return """# CDP v7 Quick Start Examples
512
+
513
+ ## Get Started in 3 Steps
514
+
515
+ ### 1. See What's Available
516
+ ```python
517
+ list_cdp_programs()
518
+ ```
519
+
520
+ ### 2. Learn How to Use It
521
+ ```python
522
+ get_cdp_usage('modify', 'speed')
523
+ ```
524
+
525
+ ### 3. Execute It
526
+ ```python
527
+ execute_cdp(['modify', 'speed', '1', 'input.wav', 'output.wav', '2.0'])
528
+ ```
529
+
530
+ ## Common Operations
531
+
532
+ ### Time Stretch (Spectral)
533
+ ```python
534
+ # Check usage
535
+ get_cdp_usage('stretch')
536
+
537
+ # Execute
538
+ execute_cdp(['stretch', 'time', '1', 'input.ana', 'output.ana', '2.0'])
539
+ ```
540
+
541
+ ### Spectral Blur
542
+ ```python
543
+ # Check usage
544
+ get_cdp_usage('blur')
545
+
546
+ # Execute (note double syntax)
547
+ execute_cdp(['blur', 'blur', 'input.ana', 'output.ana', '50'])
548
+ ```
549
+
550
+ ### Granular Synthesis
551
+ ```python
552
+ # Check usage
553
+ get_cdp_usage('modify', 'brassage')
554
+
555
+ # Execute
556
+ execute_cdp(['modify', 'brassage', '4', 'input.wav', 'output.wav', '0.02', '-0.5', '-r200'])
557
+ ```
558
+
559
+ ### Convert to Mono
560
+ ```python
561
+ # Check usage
562
+ get_cdp_usage('housekeep', 'chans')
563
+
564
+ # Execute
565
+ execute_cdp(['housekeep', 'chans', '4', 'stereo.wav', 'mono.wav'])
566
+ ```
567
+
568
+ ### Spectral Analysis
569
+ ```python
570
+ # Using helper
571
+ prepare_spectral('input.wav', 'output.ana', 2048)
572
+
573
+ # Or directly
574
+ execute_cdp(['pvoc', 'anal', '1', 'input.wav', 'output.ana', '-c2048'])
575
+ ```
576
+
577
+ ### Tesselate with Data File
578
+ ```python
579
+ # Check usage
580
+ get_cdp_usage('tesselate')
581
+ # See it needs a DATAFILE with repeat counts and delays
582
+
583
+ # Create the data file
584
+ create_data_file('tess_data.txt', '5 5 5 5\\n0.0 0.1 0.2 0.3')
585
+
586
+ # Execute with data file
587
+ execute_cdp(['tesselate', 'tesselate', '1', 'in1.wav', 'in2.wav', 'in3.wav', 'in4.wav', 'output.wav', '0.5', 'tess_data.txt'])
588
+ ```
589
+
590
+ ## Remember
591
+
592
+ - Read usage first with get_cdp_usage()
593
+ - Create data files when usage mentions DATAFILE
594
+ - Build exact command arrays
595
+ - Check output file existence for success
596
+ - CDP may return non-zero exit codes even when successful
597
+ """
598
+
599
+ def main():
600
+ """Entry point for running the MCP server"""
601
+ mcp.run()
602
+
603
+ if __name__ == "__main__":
604
+ main()
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 David Piazza
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.
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: iflow-mcp_davidpiazza-cdp_mcp
3
+ Version: 1.0.0
4
+ Summary: CDP MCP Server - Direct access to Composers' Desktop Project sound transformation programs
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.8
7
+ Requires-Dist: mcp>=1.0.0
8
+ Requires-Dist: numpy>=1.24.0
9
+ Requires-Dist: soundfile>=0.12.1
10
+ Description-Content-Type: text/markdown
11
+
12
+ # CDP MCP Server
13
+
14
+ A Model Context Protocol (MCP) server that provides direct access to the Composers' Desktop Project (CDP) sound transformation programs. This server offers an ultra-rigid workflow with zero interpretation, exposing CDP's raw functionality through simple, reliable tools.
15
+
16
+ ## Overview
17
+
18
+ CDP MCP Server v7 implements a minimalist approach to CDP integration:
19
+ - **Direct execution** - No command parsing or interpretation
20
+ - **Raw usage text** - See exactly what CDP shows
21
+ - **Simple tools** - Just 6 core functions
22
+ - **Data file support** - Create parameter files for complex operations
23
+
24
+ ## Features
25
+
26
+ - 🎵 **Full CDP Access** - Execute any CDP program with complete control
27
+ - 📚 **Program Discovery** - List all available CDP programs by category
28
+ - 📖 **Usage Information** - Get raw usage text directly from CDP
29
+ - 📄 **Data File Creation** - Create parameter files required by CDP programs
30
+ - 🎛️ **Spectral Preparation** - Helper for PVOC analysis
31
+ - 📊 **Sound Analysis** - Get basic properties of audio files
32
+
33
+ ## Requirements
34
+
35
+ ### System Requirements
36
+ - macOS, Linux, or Windows
37
+ - Python 3.8 or higher
38
+ - CDP (Composers' Desktop Project) installed
39
+
40
+ ### Python Dependencies
41
+ ```
42
+ mcp
43
+ soundfile
44
+ numpy
45
+ ```
46
+
47
+ ### CDP Installation
48
+ 1. Download CDP from the [official website](https://www.unstablesound.net/cdp.html)
49
+ 2. Install CDP following the platform-specific instructions
50
+ 3. Set the `CDP_PATH` environment variable to your CDP programs directory:
51
+ ```bash
52
+ export CDP_PATH="/path/to/cdp/programs"
53
+ ```
54
+
55
+ ## Installation
56
+
57
+ ### 1. Clone the Repository
58
+ ```bash
59
+ git clone https://github.com/DavidPiazza/CDP_MCP.git
60
+ cd CDP_MCP
61
+ ```
62
+
63
+ ### 2. Install Dependencies
64
+ ```bash
65
+ pip install -r requirements.txt
66
+ ```
67
+
68
+ Or install individually:
69
+ ```bash
70
+ pip install mcp soundfile numpy
71
+ ```
72
+
73
+ ### 3. Configure CDP Path
74
+ Set your CDP installation path:
75
+ ```bash
76
+ export CDP_PATH="/Users/yourname/cdpr8/_cdp/_cdprogs" # macOS example
77
+ ```
78
+
79
+ ### 4. Run the Server
80
+ ```bash
81
+ python CDP_MCP_v7.py
82
+ ```
83
+
84
+ ## MCP Client Configuration
85
+
86
+ To use this server with an MCP client (like Claude Desktop), add to your configuration:
87
+
88
+ ```json
89
+ {
90
+ "mcpServers": {
91
+ "cdp": {
92
+ "command": "python",
93
+ "args": ["/path/to/CDP_MCP_v7.py"],
94
+ "env": {
95
+ "CDP_PATH": "/path/to/cdp/programs"
96
+ }
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ ## Usage
103
+
104
+ ### Basic Workflow
105
+
106
+ 1. **List Available Programs**
107
+ ```python
108
+ list_cdp_programs()
109
+ # Returns categorized list of all CDP programs
110
+ ```
111
+
112
+ 2. **Get Program Usage**
113
+ ```python
114
+ get_cdp_usage('blur')
115
+ # Returns exact CDP usage text
116
+ ```
117
+
118
+ 3. **Execute Commands**
119
+ ```python
120
+ execute_cdp(['blur', 'blur', 'input.ana', 'output.ana', '50'])
121
+ # Direct execution with no interpretation
122
+ ```
123
+
124
+ ### Example Operations
125
+
126
+ #### Time Stretch
127
+ ```python
128
+ # Check usage
129
+ get_cdp_usage('stretch')
130
+
131
+ # Execute
132
+ execute_cdp(['stretch', 'time', '1', 'input.ana', 'output.ana', '2.0'])
133
+ ```
134
+
135
+ #### Spectral Blur
136
+ ```python
137
+ # Note the double syntax for blur
138
+ execute_cdp(['blur', 'blur', 'input.ana', 'output.ana', '50'])
139
+ ```
140
+
141
+ #### Granular Synthesis
142
+ ```python
143
+ execute_cdp(['modify', 'brassage', '4', 'input.wav', 'output.wav', '0.02', '-0.5', '-r200'])
144
+ ```
145
+
146
+ #### Using Data Files
147
+ ```python
148
+ # Create data file for tesselate
149
+ create_data_file('tess_data.txt', '5 5 5 5\n0.0 0.1 0.2 0.3')
150
+
151
+ # Execute with data file
152
+ execute_cdp(['tesselate', 'tesselate', '1', 'in1.wav', 'in2.wav', 'in3.wav', 'in4.wav', 'output.wav', '0.5', 'tess_data.txt'])
153
+ ```
154
+
155
+ ## Tools Reference
156
+
157
+ ### `list_cdp_programs()`
158
+ Lists all available CDP programs organized by category (Spectral Processing, Time Domain, Synthesis, etc.)
159
+
160
+ ### `get_cdp_usage(program, subprogram=None)`
161
+ Returns raw usage information for a CDP program by running it without arguments.
162
+
163
+ ### `execute_cdp(command)`
164
+ Executes a CDP command given as an array of strings. No parsing or interpretation.
165
+
166
+ ### `create_data_file(filepath, content)`
167
+ Creates text data files required by certain CDP programs.
168
+
169
+ ### `prepare_spectral(input_file, output_file, window_size=2048)`
170
+ Helper function to perform PVOC analysis for spectral processing.
171
+
172
+ ### `analyze_sound(filepath)`
173
+ Returns basic properties of a sound file (duration, sample rate, channels, etc.)
174
+
175
+ ## Architecture
176
+
177
+ The server follows an ultra-rigid design philosophy:
178
+ - **No command parsing** - Commands are arrays, not strings
179
+ - **No parameter validation** - CDP handles all validation
180
+ - **No output interpretation** - Raw CDP output is returned
181
+ - **Minimal abstraction** - Direct CDP access only
182
+
183
+ ## Tips
184
+
185
+ - Always check usage with `get_cdp_usage()` before executing
186
+ - CDP may return non-zero exit codes even on success
187
+ - Check if output files exist to verify successful execution
188
+ - Use exact command arrays - the server does no interpretation
189
+ - Create data files when CDP usage mentions DATAFILE requirements
190
+
191
+ ## Troubleshooting
192
+
193
+ ### CDP Not Found
194
+ Ensure `CDP_PATH` environment variable points to your CDP programs directory.
195
+
196
+ ### Apple Silicon Issues
197
+ The server automatically handles x86_64 emulation on Apple Silicon Macs using `arch -x86_64`.
198
+
199
+ ### Command Failures
200
+ 1. Check the exact usage with `get_cdp_usage()`
201
+ 2. Verify all file paths exist
202
+ 3. Ensure proper command array format
203
+ 4. Check CDP's stderr output for specific errors
204
+
205
+ ## License
206
+
207
+ MIT License - See LICENSE file for details
208
+
209
+ ## Acknowledgments
210
+
211
+ - [Composers' Desktop Project](https://www.unstablesound.net/cdp.html) for the amazing sound transformation tools
212
+ - [Model Context Protocol](https://github.com/anthropics/model-context-protocol) for the MCP framework
@@ -0,0 +1,201 @@
1
+ # CDP MCP Server
2
+
3
+ A Model Context Protocol (MCP) server that provides direct access to the Composers' Desktop Project (CDP) sound transformation programs. This server offers an ultra-rigid workflow with zero interpretation, exposing CDP's raw functionality through simple, reliable tools.
4
+
5
+ ## Overview
6
+
7
+ CDP MCP Server v7 implements a minimalist approach to CDP integration:
8
+ - **Direct execution** - No command parsing or interpretation
9
+ - **Raw usage text** - See exactly what CDP shows
10
+ - **Simple tools** - Just 6 core functions
11
+ - **Data file support** - Create parameter files for complex operations
12
+
13
+ ## Features
14
+
15
+ - 🎵 **Full CDP Access** - Execute any CDP program with complete control
16
+ - 📚 **Program Discovery** - List all available CDP programs by category
17
+ - 📖 **Usage Information** - Get raw usage text directly from CDP
18
+ - 📄 **Data File Creation** - Create parameter files required by CDP programs
19
+ - 🎛️ **Spectral Preparation** - Helper for PVOC analysis
20
+ - 📊 **Sound Analysis** - Get basic properties of audio files
21
+
22
+ ## Requirements
23
+
24
+ ### System Requirements
25
+ - macOS, Linux, or Windows
26
+ - Python 3.8 or higher
27
+ - CDP (Composers' Desktop Project) installed
28
+
29
+ ### Python Dependencies
30
+ ```
31
+ mcp
32
+ soundfile
33
+ numpy
34
+ ```
35
+
36
+ ### CDP Installation
37
+ 1. Download CDP from the [official website](https://www.unstablesound.net/cdp.html)
38
+ 2. Install CDP following the platform-specific instructions
39
+ 3. Set the `CDP_PATH` environment variable to your CDP programs directory:
40
+ ```bash
41
+ export CDP_PATH="/path/to/cdp/programs"
42
+ ```
43
+
44
+ ## Installation
45
+
46
+ ### 1. Clone the Repository
47
+ ```bash
48
+ git clone https://github.com/DavidPiazza/CDP_MCP.git
49
+ cd CDP_MCP
50
+ ```
51
+
52
+ ### 2. Install Dependencies
53
+ ```bash
54
+ pip install -r requirements.txt
55
+ ```
56
+
57
+ Or install individually:
58
+ ```bash
59
+ pip install mcp soundfile numpy
60
+ ```
61
+
62
+ ### 3. Configure CDP Path
63
+ Set your CDP installation path:
64
+ ```bash
65
+ export CDP_PATH="/Users/yourname/cdpr8/_cdp/_cdprogs" # macOS example
66
+ ```
67
+
68
+ ### 4. Run the Server
69
+ ```bash
70
+ python CDP_MCP_v7.py
71
+ ```
72
+
73
+ ## MCP Client Configuration
74
+
75
+ To use this server with an MCP client (like Claude Desktop), add to your configuration:
76
+
77
+ ```json
78
+ {
79
+ "mcpServers": {
80
+ "cdp": {
81
+ "command": "python",
82
+ "args": ["/path/to/CDP_MCP_v7.py"],
83
+ "env": {
84
+ "CDP_PATH": "/path/to/cdp/programs"
85
+ }
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## Usage
92
+
93
+ ### Basic Workflow
94
+
95
+ 1. **List Available Programs**
96
+ ```python
97
+ list_cdp_programs()
98
+ # Returns categorized list of all CDP programs
99
+ ```
100
+
101
+ 2. **Get Program Usage**
102
+ ```python
103
+ get_cdp_usage('blur')
104
+ # Returns exact CDP usage text
105
+ ```
106
+
107
+ 3. **Execute Commands**
108
+ ```python
109
+ execute_cdp(['blur', 'blur', 'input.ana', 'output.ana', '50'])
110
+ # Direct execution with no interpretation
111
+ ```
112
+
113
+ ### Example Operations
114
+
115
+ #### Time Stretch
116
+ ```python
117
+ # Check usage
118
+ get_cdp_usage('stretch')
119
+
120
+ # Execute
121
+ execute_cdp(['stretch', 'time', '1', 'input.ana', 'output.ana', '2.0'])
122
+ ```
123
+
124
+ #### Spectral Blur
125
+ ```python
126
+ # Note the double syntax for blur
127
+ execute_cdp(['blur', 'blur', 'input.ana', 'output.ana', '50'])
128
+ ```
129
+
130
+ #### Granular Synthesis
131
+ ```python
132
+ execute_cdp(['modify', 'brassage', '4', 'input.wav', 'output.wav', '0.02', '-0.5', '-r200'])
133
+ ```
134
+
135
+ #### Using Data Files
136
+ ```python
137
+ # Create data file for tesselate
138
+ create_data_file('tess_data.txt', '5 5 5 5\n0.0 0.1 0.2 0.3')
139
+
140
+ # Execute with data file
141
+ execute_cdp(['tesselate', 'tesselate', '1', 'in1.wav', 'in2.wav', 'in3.wav', 'in4.wav', 'output.wav', '0.5', 'tess_data.txt'])
142
+ ```
143
+
144
+ ## Tools Reference
145
+
146
+ ### `list_cdp_programs()`
147
+ Lists all available CDP programs organized by category (Spectral Processing, Time Domain, Synthesis, etc.)
148
+
149
+ ### `get_cdp_usage(program, subprogram=None)`
150
+ Returns raw usage information for a CDP program by running it without arguments.
151
+
152
+ ### `execute_cdp(command)`
153
+ Executes a CDP command given as an array of strings. No parsing or interpretation.
154
+
155
+ ### `create_data_file(filepath, content)`
156
+ Creates text data files required by certain CDP programs.
157
+
158
+ ### `prepare_spectral(input_file, output_file, window_size=2048)`
159
+ Helper function to perform PVOC analysis for spectral processing.
160
+
161
+ ### `analyze_sound(filepath)`
162
+ Returns basic properties of a sound file (duration, sample rate, channels, etc.)
163
+
164
+ ## Architecture
165
+
166
+ The server follows an ultra-rigid design philosophy:
167
+ - **No command parsing** - Commands are arrays, not strings
168
+ - **No parameter validation** - CDP handles all validation
169
+ - **No output interpretation** - Raw CDP output is returned
170
+ - **Minimal abstraction** - Direct CDP access only
171
+
172
+ ## Tips
173
+
174
+ - Always check usage with `get_cdp_usage()` before executing
175
+ - CDP may return non-zero exit codes even on success
176
+ - Check if output files exist to verify successful execution
177
+ - Use exact command arrays - the server does no interpretation
178
+ - Create data files when CDP usage mentions DATAFILE requirements
179
+
180
+ ## Troubleshooting
181
+
182
+ ### CDP Not Found
183
+ Ensure `CDP_PATH` environment variable points to your CDP programs directory.
184
+
185
+ ### Apple Silicon Issues
186
+ The server automatically handles x86_64 emulation on Apple Silicon Macs using `arch -x86_64`.
187
+
188
+ ### Command Failures
189
+ 1. Check the exact usage with `get_cdp_usage()`
190
+ 2. Verify all file paths exist
191
+ 3. Ensure proper command array format
192
+ 4. Check CDP's stderr output for specific errors
193
+
194
+ ## License
195
+
196
+ MIT License - See LICENSE file for details
197
+
198
+ ## Acknowledgments
199
+
200
+ - [Composers' Desktop Project](https://www.unstablesound.net/cdp.html) for the amazing sound transformation tools
201
+ - [Model Context Protocol](https://github.com/anthropics/model-context-protocol) for the MCP framework
@@ -0,0 +1 @@
1
+ python
@@ -0,0 +1 @@
1
+ iflow-mcp_davidpiazza-cdp_mcp
@@ -0,0 +1,5 @@
1
+ {
2
+ "push_platform": "github",
3
+ "fork_url": "https://github.com/iflow-mcp/davidpiazza-cdp_mcp",
4
+ "fork_branch": "iflow"
5
+ }
@@ -0,0 +1,21 @@
1
+ [project]
2
+ name = "iflow-mcp_davidpiazza-cdp_mcp"
3
+ version = "1.0.0"
4
+ description = "CDP MCP Server - Direct access to Composers' Desktop Project sound transformation programs"
5
+ readme = "README.md"
6
+ requires-python = ">=3.8"
7
+ dependencies = [
8
+ "mcp>=1.0.0",
9
+ "soundfile>=0.12.1",
10
+ "numpy>=1.24.0",
11
+ ]
12
+
13
+ [project.scripts]
14
+ cdp-mcp = "CDP_MCP_v7:main"
15
+
16
+ [build-system]
17
+ requires = ["hatchling"]
18
+ build-backend = "hatchling.build"
19
+
20
+ [tool.hatch.build.targets.wheel]
21
+ packages = ["CDP_MCP_v7.py"]
@@ -0,0 +1,3 @@
1
+ mcp
2
+ soundfile>=0.12.1
3
+ numpy>=1.24.0