← LavSange

MCP-server

MCP-serveren sætter LavSange direkte ind i AI-agenter. Claude, Cursor eller din egen agent kan få skrevet og produceret en sang midt i en samtale, uden at nogen bygger et REST-kald i hånden.

Opdateret: 2026-09-16

Anmod om adgang

Nøgler udstedes manuelt. En kort mail med dit formål, forventet volumen og sprog er nok, og adgangen plejer at tage én hverdag.

Anmod om adgang

Introduktion

Model Context Protocol er en åben standard for, hvordan en AI-agent når eksterne værktøjer og data. I stedet for at skrive en API-klient tilføjer du serveren én gang til agentens opsætning. Derefter kender modellen værktøjerne og kalder dem selv, når samtalen lægger op til det.

Vores server kan det samme som REST-API’et: få skrevet og produceret en sang, tjekke status, hente sangteksten, generere på ny, lave et betalingslink. Forskellen ligger i indpakningen. Værktøjsbeskrivelserne er formuleret, så en model forstår hvornår en sang overhovedet giver mening, og hvilke oplysninger den bør samle ind først.

Adressen er https://mcp.lavsange.dk/mcp. Det er den samme tjeneste som på /api/, bare med en anden indpakning, og den bruger de samme nøgler. Kører du begge dele, ser du de samme sange begge steder.

Også her afregnes der kun pr. færdig sang, aktuelt 249 DKK. Værktøjskald der kun læser eller forbereder noget, koster ingenting.

Adgang

Vejen er den samme som ved REST-API’et: nøgler udstedes manuelt. Skriv til songs@maxkuch.com og fortæl kort, hvilken agent du vil koble på, hvad den skal kunne, og hvilket volumen der er tale om.

Du får en testnøgle (sk_test_) og en livenøgle (sk_live_). Har du allerede en API-nøgle, skal du ikke bruge en ny: den samme nøgle åbner MCP-serveren.

Til teams der vil stille serveren til rådighed for flere personer, udsteder vi på ønske flere nøgler med fælles afregning. Så kan man bagefter se, hvilken nøgle der har lavet hvilken sang.

Forbindelse og transport

Serveren taler MCP over HTTP med server-sent events i returretningen, altså den transport de aktuelle klienter bruger som standard. Der skal ikke køre en lokal proces, og der er ikke noget at installere.

Autentificeringen bruger den samme Authorization-header som REST-API’et: Authorization: Bearer sk_live_.... Klienter der kun kan stdio, når serveren via mcp-remote som bro, se opsætningen til Claude Desktop nedenfor.

Klient og server forhandler protokolversionen ved opkobling. Vi understøtter den aktuelle udgave og den forrige, så en klientopdatering aldrig giver et hårdt brud.

bashTjek at serveren svarer
curl https://mcp.lavsange.dk/health

Opsætning

I Claude Code er én kommando nok. Nøglen bør komme fra en miljøvariabel og ikke fra udklipsholderen.

bashClaude Code
claude mcp add --transport http songs \
  https://mcp.lavsange.dk/mcp \
  --header "Authorization: Bearer $SONG_API_KEY"

Claude Desktop

Claude Desktop læser sin serverliste fra claude_desktop_config.json. Posten bygger bro til HTTP-transporten via mcp-remote.

jsonclaude_desktop_config.json
{
  "mcpServers": {
    "songs": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://mcp.lavsange.dk/mcp",
               "--header", "Authorization: Bearer ${SONG_API_KEY}"],
      "env": { "SONG_API_KEY": "sk_live_..." }
    }
  }
}

Cursor og andre klienter

Cursor, Windsurf, Zed og de fleste andre klienter tager server-URL’en direkte og tillader egne headere. Så er broen overflødig.

json.cursor/mcp.json
{
  "mcpServers": {
    "songs": {
      "url": "https://mcp.lavsange.dk/mcp",
      "headers": { "Authorization": "Bearer sk_live_..." }
    }
  }
}

Når posten er tilføjet, bør klienten vise syv værktøjer. Dukker listen ikke op, skyldes det næsten altid headeren: en udløbet eller forkert kopieret nøgle giver en tom værktøjsliste i stedet for en synlig fejl.

Værktøjer

Serveren stiller syv værktøjer til rådighed. Skrivende værktøjer er markeret som sådan, så klienter kan bede om bekræftelse hvor de vil.

VærktøjTypeBeskrivelse
create_songSkriver og producerer en sang. Vender straks tilbage med et sang-id, indspilningen følger få minutter senere. På ønske blokerer kaldet til smagsprøven er klar.
get_songGiver en sangs aktuelle tilstand med status, smagsprøvelink og betalingsstatus.
list_songsLister de senest lavede sange, eventuelt filtreret på status. Nyttigt når agenten tager tråden op igen efter en pause.
get_lyricsGiver den fulde sangtekst som tekst. Teksten er altid gratis, også før betaling.
regenerate_songLaver en ny version, enten med samme tekst og ny indspilning eller helt forfra. Op til tre gange pr. sang, uden ekstra omkostning.
get_checkout_linkLaver et betalingslink til en sang og giver det som URL, så agenten kan sende det videre i samtalen.
list_optionsNævner de gyldige værdier for anledning, stemning, stemme og sprog. Agenter bør hente dem én gang pr. session i stedet for at gætte.

Læsende værktøjer er idempotente og må kaldes uden at spørge. create_song og regenerate_song ændrer tilstand og udløser produktionsomkostninger, derfor melder de sig til klienten som skrivende.

create_song i detaljer

Det vigtigste værktøj er create_song. Skemaet er bevidst smalt: tre påkrævede felter, resten valgfrit med fornuftige standardværdier. Jo færre valg en model skal træffe, jo sjældnere finder den på værdier.

jsonVærktøjsskema
{
  "name": "create_song",
  "description": "Write and produce a personalised song. Returns immediately with a song id; the recording is ready a few minutes later.",
  "inputSchema": {
    "type": "object",
    "required": ["occasion", "recipient_name", "details"],
    "properties": {
      "occasion":       { "type": "string", "enum": ["birthday", "wedding", "anniversary", "farewell", "funeral", "christening", "graduation", "christmas", "declaration", "other"] },
      "recipient_name": { "type": "string", "maxLength": 80 },
      "relationship":   { "type": "string", "maxLength": 80 },
      "language":       { "type": "string", "default": "da" },
      "mood":           { "type": "string", "enum": ["happy", "warm", "funny", "romantic", "gentle", "epic", "surprise_me"] },
      "style":          { "type": "string" },
      "voice":          { "type": "string", "enum": ["female", "male", "duet", "choir", "childrens", "surprise_me"] },
      "details":        { "type": "string", "minLength": 40, "maxLength": 4000 },
      "wait":           { "type": "boolean", "default": false, "description": "Block until the preview is ready, at most 10 minutes." }
    }
  }
}

Løftestangen er details. Der hører konkrete ting hjemme: kælenavne, fælles oplevelser, særheder, løbende vitser. En sang bygget på tre tillægsord lyder som tre tillægsord. Fyrre tegn er minimum, og værktøjets beskrivelse siger udtrykkeligt til modellen, at den skal spørge i stedet for at finde på detaljer.

Feltet wait styrer ventetiden. Standard er false: kaldet vender straks tilbage, agenten kan tale videre og kalde get_song senere. Med true blokerer kaldet indtil smagsprøven på 45 sekunder findes, højst ti minutter. For samtaleagenter er false næsten altid det bedste valg.

Uden language synges sangen på da, dette domænes sprog. Alle gængse europæiske sprog og japansk er mulige, og list_options giver den gyldige liste.

Svarformat

Værktøjer svarer ad to spor: en tekstblok til modellen og, hvor det giver mening, structuredContent til klienten. Tekstblokken er formuleret, så modellen kan læse den direkte op for brugeren uden at oversætte den.

jsonSvar fra create_song
{
  "content": [
    { "type": "text", "text": "Song sng_3n8Kd2ZpQv for Anna is written. Lyrics below, the 45 second preview is ready." },
    { "type": "resource", "resource": { "uri": "song://sng_3n8Kd2ZpQv/lyrics", "mimeType": "text/plain" } },
    { "type": "resource", "resource": { "uri": "song://sng_3n8Kd2ZpQv/preview", "mimeType": "audio/mpeg" } }
  ],
  "structuredContent": {
    "id": "sng_3n8Kd2ZpQv",
    "status": "preview_ready",
    "preview_url": "https://cdn.lavsange.dk/preview/sng_3n8Kd2ZpQv.mp3",
    "paid": false
  },
  "isError": false
}

Sangtekst og lyd kommer retur som ressourcehenvisninger, ikke som indlejrede data. En klient der kan afspille lyd, slår henvisningen op. En klient der ikke kan, ignorerer den og beholder teksten. Sådan havner en MP3-fil aldrig i kontekstvinduet.

Betalte sange bærer desuden audio_url i structuredContent med hele indspilningen. Linket er gyldigt i 24 timer og kan til enhver tid fornys via get_song.

Ressourcer

Ud over værktøjer stiller serveren ressourcer til rådighed under skemaet song://. Klienter der understøtter ressourcer, kan vise dem eller hæfte dem på modellen uden at kalde et værktøj.

textRessource-URI’er
song://sng_3n8Kd2ZpQv           the song object as JSON
song://sng_3n8Kd2ZpQv/lyrics    the full lyrics as plain text
song://sng_3n8Kd2ZpQv/preview   the first 45 seconds as audio/mpeg
song://sng_3n8Kd2ZpQv/audio     the full recording, only after payment

Listen over tilgængelige ressourcer ændrer sig under sessionen, efterhånden som nye sange opstår. Serveren sender i så fald en ændringsbesked, så klienter kan opdatere deres liste.

Ressourcen audio findes først efter betaling. Et opslag før det er ikke en fejl i teknisk forstand, men giver en besked med betalingslinket retur.

Prompts

Til de hyppigste anledninger ligger der færdige prompts. De samler de oplysninger en god sang kræver, og kalder derefter create_song. I klienter der understøtter prompts, optræder de som hurtigkommandoer.

jsonPrompt-definition
{
  "name": "birthday_song",
  "description": "Collects the five things a birthday song needs and then creates it.",
  "arguments": [
    { "name": "recipient_name", "required": true },
    { "name": "age",            "required": false },
    { "name": "details",        "required": false }
  ]
}

Lige nu findes birthday_song, wedding_song, farewell_song og christmas_song. Foretrækker du dit eget forløb, ignorerer du bare prompterne og kalder værktøjerne direkte.

Eksempel på en samtale

Sådan ser forløbet ud i praksis. Agenten samler detaljer, kalder værktøjet, leverer tekst og smagsprøve og tager rettelser imod.

textUdskrift
User:  My sister Anna turns 34 on Friday. She climbs, she is always late,
       and she calls everyone chef. Make her a song.

Claude: [calls create_song with occasion=birthday, recipient_name=Anna,
        relationship=sister, mood=funny, details="climbs every weekend,
        always ten minutes late, calls everyone chef"]

        Done. Here are the lyrics, and the first 45 seconds are playable
        right away. Should the chorus lean more on the climbing or more
        on the chef thing?

User:  More chef.

Claude: [calls regenerate_song with keep_lyrics=false,
        note="put the chef running gag in the chorus"]

        New version is running, about five minutes.

Andet skridt er det interessante: en ny generering koster ingenting og tager igen få minutter. Det er præcis derfor smagsprøven findes, og agenter bør tilbyde den aktivt i stedet for at behandle den første version som endelig.

Betaling

En agent kan ikke udløse en betaling. Den kan kun lave et betalingslink og sende det videre, og der betales i browseren. Det er bevidst: en model skal ikke træffe en købsbeslutning, som et menneske ikke har set.

get_checkout_link giver en URL, der er gyldig i 24 timer. Efter betalingen skifter sangen til complete, og ved næste get_song ligger hele indspilningen klar. Agenten skal ikke abonnere på noget, et senere kald er nok.

Afvikler du betalingen i dit eget system og afregner kun med os, åbner vi på forespørgsel den direkte vej fra REST-API’et. Så bortfalder betalingslinket, og sangen frigives med det samme.

Tilladelser

Hver nøgle bærer tilladelser. Standard er læs og skriv uden adgang til afregning, hvilket passer til de fleste agenter.

TilladelseNavnBetydning
songs:readHente sange, liste dem, læse sangtekster. Uden denne tilladelse melder serveren en tom værktøjsliste.
songs:writeLave og genskabe sange. Udløser produktionsomkostninger.
billingLave betalingslinks og læse betalingsstatus. Kun nødvendigt hvis agenten skal sende links videre.

Værktøjer som nøglen ikke har tilladelse til, optræder slet ikke i værktøjslisten. Det er rarere end en fejlbesked midt i samtalen, fordi modellen så ikke tilbyder noget den alligevel ikke kan.

Fejlhåndtering

Fejl kommer retur som et almindeligt værktøjsresultat med isError: true, ikke som en protokolfejl. Teksten er henvendt til modellen og siger hvad der skal gøres, så agenten kan reagere fornuftigt i samtalen.

jsonFejlresultat
{
  "content": [
    { "type": "text", "text": "The song is not paid for yet, so the full recording cannot be handed over. The checkout link is https://pay.lavsange.dk/c/cs_live_8Hd2Kq..." }
  ],
  "isError": true
}

Egentlige protokolfejl opstår kun ved ugyldig nøgle, manglende tilladelse eller et ødelagt kald. Alt der kan gå galt fagligt, altså manglende oplysninger, ubetalt sang eller nået grænse, kommer retur som tekst.

Produktioner der går i stå, ender i status failed efter 15 minutter og koster ingenting. Agenten kan derefter bare kalde igen.

Grænser

Der gælder de samme grænser som i REST-API’et: 60 værktøjskald i minuttet pr. nøgle, højst ti samtidige produktioner, op til tre nye genereringer pr. sang. Højere tal kræver bare en mail.

En overskredet grænse giver ikke en hård fejl, men et tekstresultat med besked om hvornår det går videre. Agenter bør så vente frem for straks at kalde igen.

Sange kan hentes i 90 dage. Derefter forsvinder de sammen med de indtastede oplysninger, og get_song melder dem som ukendte.

Data og rettigheder

Oplysningerne fra details går udelukkende til produktionen af den pågældende sang. Vi træner ikke egne modeller på dem. En sang kan til enhver tid slettes tidligere via DELETE /v1/songs/{id} i REST-API’et.

Til den færdige sang får du en ikke-eksklusiv, udtrykkeligt kommerciel brugsret. Om der opstår en selvstændig ophavsret til en AI-skabt indspilning, er endnu ikke afklaret i mange retssystemer. Er du afhængig af det, bør du få det vurderet først.

Videregiver din agent oplysninger om dine kunder til os, er du dataansvarlig og vi databehandler. En databehandleraftale får du på forespørgsel.

Drift

Serveren kører på den samme infrastruktur som REST-API’et. Vedligeholdelsesvinduer varsler vi på mail til den oplyste adresse, og ændringer i værktøjsskemaer er udelukkende additive.

Kommer der et nyt værktøj til, sender serveren en ændringsbesked. Klienter der reagerer på den, ser det uden genstart. Eksisterende værktøjer beholder deres navne og deres påkrævede felter.

Support

Spørgsmål, højere grænser, egne prompts eller værktøjer til et bestemt forløb: songs@maxkuch.com. Nævn ved tekniske problemer sang-id’et, så finder vi kaldet med det samme.

Vil du hellere arbejde direkte mod HTTP, findes de samme muligheder som REST-grænseflade på /api/. Begge veje deler nøgler, grænser og afregning.

Anmod om adgang

Nøgler udstedes manuelt. En kort mail med dit formål, forventet volumen og sprog er nok, og adgangen plejer at tage én hverdag.

Anmod om adgang