CHUK Music MCP Server

CHUK Music MCP Server

Enables AI-assisted music composition through copyable pattern templates, style constraints, and arrangement tools that compile to MIDI files. Provides 30+ tools for managing musical structures, layers, patterns, and styles with deterministic compilation from YAML arrangements.

Category
访问服务器

README

CHUK Music MCP Server

A music design system for MCP — shadcn/ui for music composition.

You copy patterns into your project, you own them, you modify them. The library provides correct primitives and well-designed starting points, not a black box.

Vision

Music as a design system, not a DAW. This is a control-plane for composition.

LLMs operate at the intent level — structure, energy, arrangement. The system handles music theory. Composers own their patterns.

Features

  • Pattern System: Copyable, ownable pattern templates (drums, bass, harmony, melody, fx)
  • Style System: Constraint bundles that constrain, suggest, and validate
  • Arrangement Model: Layers × Sections structure with energy curves and harmony
  • Score IR: Versioned intermediate representation — golden-file testable, diffable, round-trippable
  • MIDI Export: Deterministic compilation from YAML to playable MIDI files
  • MCP Integration: Full MCP server with 37+ tools for AI-assisted composition

Quick Start

# Install
git clone https://github.com/chuk-ai/chuk-mcp-music
cd chuk-mcp-music
pip install -e ".[dev]"

# Compile an arrangement
python examples/compile_arrangement.py

# Verify determinism
shasum output/demo.mid
# e3b0c442...  (always the same for the same input)

The Stack

Intent (LLM)
    ↓
Tokens (semantic constraints)
    ↓
Structure (sections, energy curves)
    ↓
Layers (drums, bass, harmony, melody, fx)
    ↓
Patterns (owned, modifiable recipes)
    ↓
Score IR (symbolic, inspectable, versioned)
    ↓
MIDI (deterministic compilation)
    ↓
Audio (optional, downstream)

What You Own vs What the Library Owns

You Own Library Owns
Patterns you copy to your project Schema definitions (pattern/v1, score_ir/v1)
Arrangement YAML files Compiler pipeline
Style overrides and customizations Validation rules
Project-specific pattern libraries Default pattern/style libraries
Output MIDI files IR specification and canonicalization

The boundary is clear: you own the content, the library owns the machinery.

Key Concepts

Patterns (The shadcn Layer)

Patterns are copyable, ownable, modifiable templates:

# patterns/bass/root-pulse.yaml
schema: pattern/v1
name: root-pulse
role: bass
pitched: true

parameters:
  density:
    type: enum
    values: [half, quarter, eighth]
    default: quarter

variants:
  driving:
    density: eighth

template:
  events:
    - degree: chord.root
      beat: 0
      velocity: $velocity_base

Arrangements (Your Composition)

# arrangements/demo.arrangement.yaml
schema: arrangement/v1
key: D_minor
tempo: 124

harmony:
  default_progression: [i, VI, III, VII]

sections:
  - name: intro
    bars: 8
  - name: verse
    bars: 16

layers:
  bass:
    role: bass
    patterns:
      pulse:
        ref: bass/root-pulse
        variant: driving
    arrangement:
      intro: null
      verse: pulse

Styles (Constraint Bundles)

Styles do three things:

  1. Constrain — tempo ranges, forbidden patterns, key preferences
  2. Suggest — pattern shortlists per layer, register hints
  3. Validate — lint errors with actionable fixes
# styles/library/melodic-techno.yaml
schema: style/v1
name: melodic-techno
description: Driving, melodic electronic music

tokens:
  tempo:
    range: [120, 128]
    default: 124
  key_preference: minor

structure_hints:
  breakdown_required: true
  section_multiples: 8

layer_hints:
  bass:
    suggested: [bass/rolling-sixteenths, bass/root-pulse]
    register: low

forbidden:
  patterns: [drums/trap-*]

Validation output:

{
  "valid": false,
  "errors": [
    {"message": "Tempo 140 outside style range [120, 128]", "severity": "error"},
    {"message": "Pattern drums/trap-hat forbidden by style", "severity": "error"}
  ],
  "suggestions": [
    {"message": "Consider drums/four-on-floor for drums layer", "severity": "info"}
  ]
}

Score IR (Intermediate Representation)

The Score IR is the stable, inspectable contract between arrangement and MIDI:

Arrangement YAML → Score IR (diffable, versioned) → MIDI

Same arrangement → same Score IR → same MIDI. Always.

Schema Excerpt (score_ir/v1)

{
  "schema": "score_ir/v1",
  "name": "my-track",
  "key": "D_minor",
  "tempo": 124,
  "time_signature": {"numerator": 4, "denominator": 4},
  "ticks_per_beat": 480,
  "total_bars": 24,
  "notes": [
    {
      "start_ticks": 0,
      "pitch": 50,
      "duration_ticks": 480,
      "velocity": 90,
      "channel": 1,
      "source_layer": "bass",
      "source_pattern": "bass/root-pulse",
      "source_section": "verse",
      "bar": 0,
      "beat": 0.0
    }
  ],
  "sections": [
    {"name": "intro", "start_ticks": 0, "end_ticks": 15360, "bars": 8}
  ]
}

Canonicalization Rules

  • Notes sorted by (start_ticks, channel, pitch)
  • Sections sorted by start_ticks
  • All times in ticks (480 ticks per beat)
  • Source traceability on every note

Usage

# Compile and inspect
result = compiler.compile(arrangement)
print(result.score_ir.summary())
# {'name': 'my-track', 'total_bars': 32, 'total_notes': 256,
#  'layers': {'drums': 128, 'bass': 64, 'harmony': 64},
#  'pitch_range': (36, 72), 'velocity_range': (60, 110)}

# Compare two versions
diff = old_ir.diff_summary(new_ir)
# {'notes_added': 12, 'notes_removed': 8, 'notes_unchanged': 244,
#  'tempo_changed': False, 'key_changed': False}

# Debug: "Why is this note here?"
for note in result.score_ir.notes:
    if note.pitch == 50 and note.bar == 3:
        print(f"From {note.source_layer}/{note.source_pattern} in {note.source_section}")

Common Workflows

1. Create Track from Style

# Apply style → suggest patterns → add sections → arrange → compile
music_apply_style(arrangement="my-track", style="melodic-techno")
music_suggest_patterns(arrangement="my-track", role="bass")
# Returns: ["bass/rolling-sixteenths", "bass/root-pulse"]

music_add_section(arrangement="my-track", name="intro", bars=8)
music_add_section(arrangement="my-track", name="verse", bars=16)
music_arrange_layer(arrangement="my-track", layer="bass",
                    section_patterns={"intro": None, "verse": "main"})
music_compile_midi(arrangement="my-track")

2. Iterate on Bassline

# Preview → tweak → diff → compile
music_preview_section(arrangement="my-track", section="verse")
music_update_pattern_params(arrangement="my-track", layer="bass",
                            params={"density": "eighth"})
music_diff_ir(arrangement="my-track-v1", other_arrangement="my-track-v2")
# {'notes_added': 32, 'notes_removed': 16, ...}

music_compile_midi(arrangement="my-track")

3. Debug a Bad Result

# Compile to IR → inspect provenance → validate → fix
result = music_compile_to_ir(arrangement="my-track")
# Inspect which pattern produced the wrong notes
# Each note has: source_layer, source_pattern, source_section, bar, beat

music_validate(arrangement="my-track")
# {"valid": false, "errors": [{"message": "Channel conflict on channel 1"}]}

# Fix the issue
music_set_layer_level(arrangement="my-track", name="bass", level=0.8)

4. Extract Stems (IR Round-Trip)

# Compile → modify IR → emit separate MIDI files
ir = music_compile_to_ir(arrangement="my-track")

# Extract just the bass layer
bass_ir = music_modify_ir(ir_json=ir["score_ir"], filter_layers=["bass"])
music_emit_midi_from_ir(ir_json=bass_ir["score_ir"], output_name="bass-stem")

# Extract drums, reduce velocity
drums_ir = music_modify_ir(ir_json=ir["score_ir"],
                           filter_layers=["drums"],
                           velocity_scale=0.8)
music_emit_midi_from_ir(ir_json=drums_ir["score_ir"], output_name="drums-stem")

# Transpose harmony up an octave
harmony_ir = music_modify_ir(ir_json=ir["score_ir"],
                             filter_layers=["harmony"],
                             transpose=12)
music_emit_midi_from_ir(ir_json=harmony_ir["score_ir"], output_name="harmony-high")

MCP Tools

The server provides 37+ tools organized by domain:

Arrangement Tools (6):

  • music_create_arrangement - Create a new arrangement
  • music_get_arrangement - Get arrangement details
  • music_list_arrangements - List all arrangements
  • music_save_arrangement - Save to YAML
  • music_delete_arrangement - Delete an arrangement
  • music_duplicate_arrangement - Clone an arrangement

Structure Tools (11):

  • music_add_section, music_remove_section, music_reorder_sections
  • music_set_section_energy, music_add_layer, music_remove_layer
  • music_arrange_layer, music_mute_layer, music_solo_layer
  • music_set_layer_level, music_set_harmony

Pattern Tools (6):

  • music_list_patterns, music_describe_pattern
  • music_add_pattern, music_remove_pattern
  • music_update_pattern_params, music_copy_pattern_to_project

Style Tools (6):

  • music_list_styles, music_describe_style
  • music_suggest_patterns, music_validate_style
  • music_apply_style, music_copy_style_to_project

Compilation Tools (8):

  • music_compile_midi, music_preview_section
  • music_compile_to_ir, music_diff_ir
  • music_modify_ir, music_emit_midi_from_ir
  • music_export_yaml, music_validate

Humanization (Planned)

Determinism doesn't mean robotic. Humanization is seeded and explicit:

# In arrangement
humanize:
  timing_ms: 8      # ±8ms timing drift
  velocity: 6       # ±6 velocity variation
  seed: 42          # Reproducible randomness

Same seed → same humanization → still deterministic. Change the seed to explore variations.

Development

# Clone and install
git clone https://github.com/chuk-ai/chuk-mcp-music
cd chuk-mcp-music
pip install -e ".[dev]"

# Run full check suite
make check    # Linting, types, security, tests (532 tests)

# Run tests with coverage
make test-cov  # Currently at 89% coverage

# Format code
ruff format .
ruff check --fix .

Project Structure

src/chuk_mcp_music/
├── core/           # Music primitives (pitch, rhythm, chord, scale)
├── models/         # Pydantic models (arrangement, pattern, style)
├── arrangement/    # Arrangement management
├── patterns/       # Pattern system and library
│   └── library/    # Built-in patterns (copy these!)
├── styles/         # Style system and library
│   └── library/    # Built-in styles
├── compiler/       # Compilation pipeline
│   ├── arranger.py # Arrangement → Score IR → MIDI
│   ├── score_ir.py # Intermediate representation (versioned, diffable)
│   └── midi.py     # MIDI file generation
├── tools/          # MCP tool implementations
└── async_server.py # MCP server entry point

Roadmap

See roadmap.md for the full design document.

Next up:

  • Export profiles (GM, Ableton, Logic drum maps)
  • CC automation lanes (filter sweeps, sidechain ducking)
  • Real-time preview via Web MIDI
  • Pattern learning from MIDI import

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选