Skip to main content
Glama
rachadchazbek

Musicians MCP

Musicians MCP Server

Python MCP server for a classical musicians database stored in Supabase/PostgreSQL.

This project now supports both:

  • trusted database read/review tools, and

  • deterministic external-source enrichment/staging tools

for MusicBrainz and Wikidata.

The MCP client is the AI agent. This server does not call any LLM APIs internally.

Features

Core database tools

  • health_check()

  • search_musicians(query: str, limit: int = 10)

  • get_musician_profile(musician_id: str)

  • create_import_job(names: list[str], job_name: str | None = None)

  • get_review_queue(limit: int = 20)

  • approve_staged_musician(staged_profile_id: str)

External-source enrichment and staging tools

  • resolve_musician_identity(name: str, limit: int = 5)

  • fetch_wikidata_profile(qid: str)

  • fetch_musicbrainz_artist(mbid: str)

  • stage_musician_from_sources(...)

  • detect_staged_profile_conflicts(staged_profile_id: str)

  • process_import_job_next(import_job_id: str)

  • process_import_job_batch(import_job_id: str, max_names: int = 5)

Related MCP server: io.github.khglynn/spotify-bulk-actions-mcp

Project Structure

.
├── .env.example
├── pyproject.toml
├── README.md
└── src
    └── musicians_mcp
        ├── __init__.py
        ├── db.py
        ├── external_sources.py
        └── server.py

Requirements

  • Python 3.11+

  • Supabase project URL

  • Supabase service role key

  • a valid MusicBrainz User-Agent string

  • a valid Wikimedia User-Agent string

Setup

python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .
cp .env.example .env

Update .env with:

SUPABASE_URL=https://your-project-ref.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-supabase-service-role-key
MUSICBRAINZ_USER_AGENT=ClassicalMusiciansMCP/0.1.0 (your-email-or-project-url)
WIKIMEDIA_USER_AGENT=ClassicalMusiciansMCP/0.1.0 (your-email-or-project-url)

User-Agent notes:

  • MusicBrainz expects a descriptive User-Agent.

  • Wikimedia also expects a descriptive User-Agent for automated access.

  • A good format is: ClassicalMusiciansMCP/0.1.0 (your-email-or-project-url)

Run the Server

source .venv/bin/activate
python -m musicians_mcp.server

Or with the installed script:

source .venv/bin/activate
musicians-mcp

Example MCP Client Config

{
  "mcpServers": {
    "musicians": {
      "command": "/absolute/path/to/Musicians MCP/.venv/bin/python",
      "args": ["-m", "musicians_mcp.server"],
      "cwd": "/absolute/path/to/Musicians MCP",
      "env": {
        "SUPABASE_URL": "https://your-project-ref.supabase.co",
        "SUPABASE_SERVICE_ROLE_KEY": "your-supabase-service-role-key",
        "MUSICBRAINZ_USER_AGENT": "ClassicalMusiciansMCP/0.1.0 (your-email-or-project-url)",
        "WIKIMEDIA_USER_AGENT": "ClassicalMusiciansMCP/0.1.0 (your-email-or-project-url)"
      },
      "disabled": false,
      "autoApprove": []
    }
  }
}

If your MCP client loads environment variables from the working directory, you can keep the values in .env instead.

Safety Rules

This server is intentionally conservative.

  • It does not write directly to musicians.

  • It does not auto-approve staged musicians.

  • It does not call approve_staged_musician during staging or batch processing.

  • It only stages facts that came from source-backed deterministic fetches.

  • It writes review signals and ambiguity details into staged rows/audit logs.

  • If identity resolution is ambiguous, it keeps the profile in review-oriented status instead of pretending the identity is verified.

Trusted promotion must still happen manually through:

  • approve_staged_musician(p_staged_profile_id uuid)

External Source Behavior

MusicBrainz

The server can:

  • search artists by name

  • fetch artist details by MBID

  • normalize aliases, artist type, country/area, life-span, disambiguation, and source URL

Wikidata

The server can:

  • search entities by name

  • fetch item details by QID

  • normalize labels, description, aliases, dates, citizenship, occupations, instruments, notable works, websites, and selected external identifiers

Request discipline

Both source clients:

  • always send configured User-Agent headers

  • apply conservative pacing

  • use retry logic for transient HTTP failures

  • log every external request

Tool Summary

health_check()

Verifies that the server can connect to Supabase.

search_musicians(query, limit=10)

Searches musicians by:

  • full_name

  • display_name

  • sort_name

  • nationality

  • primary_role

Returns:

  • id

  • full_name

  • display_name

  • nationality

  • primary_role

  • birth_date

  • death_date

  • confidence

  • is_verified

get_musician_profile(musician_id)

Returns a single trusted musician plus related:

  • fact_claims

  • external_identifiers

create_import_job(names, job_name=None)

Creates an import job and returns:

  • job_id

  • total_names

  • status

get_review_queue(limit=20)

Reads staged profiles from staged_musician_review_queue.

approve_staged_musician(staged_profile_id)

Manually approves a staged profile through the Postgres RPC.

resolve_musician_identity(name, limit=5)

Searches both Wikidata and MusicBrainz and returns ranked normalized candidates.

Each candidate includes:

  • source

  • external_id

  • name

  • description / disambiguation

  • birth_date

  • death_date

  • country

  • roles

  • match_score

  • source_url

This tool does not write to the database.

fetch_wikidata_profile(qid)

Fetches and normalizes one Wikidata item.

Returns:

  • structured profile data

  • raw key fields useful for debugging

This tool does not write to the database.

fetch_musicbrainz_artist(mbid)

Fetches and normalizes one MusicBrainz artist.

Returns:

  • structured profile data

  • raw key fields useful for debugging

This tool does not write to the database.

stage_musician_from_sources(...)

Resolves and stages a musician from deterministic external sources.

Behavior:

  • if explicit external IDs are provided, it fetches those exact profiles

  • otherwise it resolves likely candidates first

  • only strong matches may be selected automatically

  • ambiguous cases remain review-oriented

  • inserts one row into staged_musician_profiles

  • inserts source-backed rows into staged_fact_claims

  • writes audit entries into import_audit_logs

  • does not write to musicians

  • does not call approval automatically

Returns:

  • staged_profile_id

  • status

  • confidence

  • selected_sources

  • warnings

detect_staged_profile_conflicts(staged_profile_id)

Checks staged facts for conflicts such as:

  • different birth dates

  • different death dates

  • different nationality/citizenship values

  • inconsistent roles/occupations

Returns property-level conflict details.

process_import_job_next(import_job_id)

Processes exactly one pending name from an import job.

It:

  • stages a single profile

  • updates processed names safely

  • writes audit logs

  • never approves automatically

process_import_job_batch(import_job_id, max_names=5)

Processes up to max_names pending names.

Returns per-name:

  • staging results

  • errors

  • job status progression

  1. Run health_check

  2. Run resolve_musician_identity("Claude Debussy")

  3. Run fetch_wikidata_profile on the selected QID

  4. Run fetch_musicbrainz_artist on the selected MusicBrainz artist ID

  5. Run create_import_job(["Claude Debussy", "Maurice Ravel"])

  6. Run process_import_job_next(job_id)

  7. Run get_review_queue()

  8. Run detect_staged_profile_conflicts(staged_profile_id)

  9. Only then run approve_staged_musician manually if the staged record is acceptable

Local Verification Commands

After setup, these are the main commands to run locally:

source .venv/bin/activate
python -m pip install -e .
python -m compileall src
python -c "import sys; sys.path.insert(0, 'src'); import musicians_mcp.server; print('server import ok')"
python -m musicians_mcp.server

Notes on Schema Flexibility

This implementation is intentionally defensive around the import/staging tables because exact column layouts were not fully specified here.

In particular, db.py uses fallback payload shapes for:

  • musician_import_jobs

  • staged_musician_profiles

  • staged_fact_claims

  • import_audit_logs

That makes the first version more resilient, but if you share the exact table schemas next, I can tighten the insert/update logic to match them precisely and reduce fallback branching.

Related MCP Connectors

Related MCP Servers