pitch-mcp
MCP server for real-time pitch detection and score alignment. Listens to a singer via microphone and reports their current position in a score and whether they are singing in tune.
What it does
Covers three goals:
- Goal 4 — Show the current measure/beat position while singing
- Goal 5 — Report pitch accuracy (too high / too low / on pitch)
- Goal 6 — Identify where in the score a singer is based on a hummed or sung phrase
Supports both offline analysis of pre-recorded audio and real-time microphone input.
Tools
| Tool | Description |
|---|---|
analyze_recording |
Offline: analyse a WAV file against a reference MusicXML score |
load_score |
Load a MusicXML score into a named session; returns a session_id |
start_monitoring |
Open the microphone and begin real-time pitch detection |
get_current_position |
Poll the current score position and pitch accuracy |
stop_monitoring |
Stop the microphone and return a session summary |
list_capabilities |
Return server metadata: pitch backend, microphone availability |
Installation
cd pitch-mcp
uv sync
For real-time monitoring (start_monitoring), PortAudio is required:
# Ubuntu / Debian
sudo apt install libportaudio2
Running
uv run pitch-mcp
Configuration
| Variable | Default | Description |
|---|---|---|
PITCH_BACKEND |
librosa |
Pitch detection algorithm: librosa or crepe |
crepe requires a manual TensorFlow install (~500 MB) and downloads ~50 MB of model weights on first use. The default librosa backend (pYIN algorithm) works well for singing voice with no extra setup.
Usage examples
// Offline analysis of a recording
{
"tool": "analyze_recording",
"arguments": {
"wav_path": "/path/to/recording.wav",
"musicxml_path": "/path/to/score.mxl",
"part_name": "Soprano"
}
}
// Real-time session
{"tool": "load_score", "arguments": {"musicxml_path": "/path/to/score.mxl", "part_name": "Alto"}}
// → returns {"session_id": "abc123"}
{"tool": "start_monitoring", "arguments": {"session_id": "abc123"}}
{"tool": "get_current_position", "arguments": {"session_id": "abc123"}}
// → returns measure, beat, expected pitch, detected pitch, accuracy
{"tool": "stop_monitoring", "arguments": {"session_id": "abc123"}}
Audio must be 16-bit PCM WAV. MP3 and FLAC are not supported.
Testing
# Unit tests (no microphone or audio required)
VIRTUAL_ENV= .venv/bin/pytest tests/ -v
# Integration tests (uses pre-recorded WAV files)
VIRTUAL_ENV= .venv/bin/pytest tests/ -v -m integration
# Manual tests (requires a real microphone — skip in CI)
VIRTUAL_ENV= .venv/bin/pytest tests/ -v -m manual
Dependencies
- librosa — pYIN pitch detection (primary backend, pure Python)
- music21 — score parsing and pitch calculations
- sounddevice — real-time microphone input
- numpy, scipy — numerics
- mcp — MCP protocol
System requirements
- Python 3.12+
libportaudio2— required for real-time microphone input (start_monitoring)- No system libraries required for offline analysis
Phase status
| Phase | Status |
|---|---|
| Phase A — offline analysis | Complete (93/93 tests pass) |
| Phase B — real-time monitoring | Session framework in place; microphone integration ready |
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pitch_mcp-0.1.3.tar.gz.
File metadata
- Download URL: pitch_mcp-0.1.3.tar.gz
- Upload date:
- Size: 145.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ee7503f3e5c6d73bc13a698d4e63d325f6143e55a23626c7187cf6dfb0e366b
|
|
| MD5 |
b90d46063dfc0f2924b42711fb81fd0f
|
|
| BLAKE2b-256 |
e9b0cd257df526fe2c0654a21cb28df8040fc19633ac67a502106a31a5ccbafb
|
Provenance
The following attestation bundles were made for pitch_mcp-0.1.3.tar.gz:
Publisher:
publish.yml on raulkivi/music-assistant
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pitch_mcp-0.1.3.tar.gz -
Subject digest:
1ee7503f3e5c6d73bc13a698d4e63d325f6143e55a23626c7187cf6dfb0e366b - Sigstore transparency entry: 2481865097
- Sigstore integration time:
-
Permalink:
raulkivi/music-assistant@7ff9527a4037d29c77405611f71c19f607945c70 -
Branch / Tag:
refs/tags/pitch-mcp/v0.1.3 - Owner: https://github.com/raulkivi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7ff9527a4037d29c77405611f71c19f607945c70 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pitch_mcp-0.1.3-py3-none-any.whl.
File metadata
- Download URL: pitch_mcp-0.1.3-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0e7beeff5c19cf9453594b7e0326ac7d9cf334013cbb007e412bb963095a52f
|
|
| MD5 |
cc5607b695855517fc3fb23a3e88b3d0
|
|
| BLAKE2b-256 |
83d331ba982fdf0c7e3bcf48eb3bce9ef07e7fca116935e141c0e0b9516a5b8b
|
Provenance
The following attestation bundles were made for pitch_mcp-0.1.3-py3-none-any.whl:
Publisher:
publish.yml on raulkivi/music-assistant
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pitch_mcp-0.1.3-py3-none-any.whl -
Subject digest:
b0e7beeff5c19cf9453594b7e0326ac7d9cf334013cbb007e412bb963095a52f - Sigstore transparency entry: 2481865143
- Sigstore integration time:
-
Permalink:
raulkivi/music-assistant@7ff9527a4037d29c77405611f71c19f607945c70 -
Branch / Tag:
refs/tags/pitch-mcp/v0.1.3 - Owner: https://github.com/raulkivi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7ff9527a4037d29c77405611f71c19f607945c70 -
Trigger Event:
push
-
Statement type: