MCP selitettynä speksiä vasten: mikä serveri oikeasti on
Yksi JSON-rivi aliprosessiin, 13 tool-määritelmää takaisin — luettuna 2026-07-28-revisiota vasten, joka poisti handshake-vaiheen.
Tällä sivulla
Asenna julkaistu MCP server, lähetä sille yksi rivi JSONia ja lue, mitä saat takaisin.
npm i @modelcontextprotocol/server-everything@2026.8.31
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| npx @modelcontextprotocol/server-everything stdio{"result":{"tools":[{"name":"echo","title":"Echo Tool","description":"Echoes
back the input string","inputSchema":{"$schema":"http://json-schema.org/draft-07/
schema#","type":"object","properties":{"message":{"type":"string","description":
"Message to echo"}},"required":["message"]},"annotations":{"readOnlyHint":true,
… … 7,663 bytes on one line …
"jsonrpc":"2.0","id":1}Kolmetoista tool-määritelmää yhdellä rivillä prosessilta, joka luki yhden rivin standardisyötteestään. Olet nyt puhunut Model Context Protocolia ilman SDK:ta, ilman client-kirjastoa ja ilman frameworkia. Siinä se kokonaisuudessaan on: transport, viestimuoto ja pieni joukko nimettyjä metodeja.
Luku 18 määritteli toolin kahdeksi asiaksi — JSON Schemaksi, jonka malli näkee, ja koodissasi olevaksi endpointiksi, jota malli ei koskaan näe. Luku 23 rakensi harnessin, joka pitää niistä katalogia. Kumpikaan ei vastannut kysymykseen, joka ratkaisee, onko mikään tästä uudelleenkäytettävää: kuka kirjoittaa skeeman, ja miten se päätyy kirjoittajalta promptiisi? MCP on yksi vastaus siihen kysymykseen, ja se kannattaa lukea alkuperäisestä lähteestä, koska lähes kaikki siitä kirjoitettu kuvaa revisiota, jota ei enää ole.
Juuri ajamassasi komennossa on kolme asiaa väärin, ja jokainen niistä on tämän luvun oma osionsa. Siinä ei ollut protokollaversiota, joten speksiä noudattavan serverin olisi pitänyt kieltäytyä siitä. Se sai silti vastauksen syystä, jota spesifikaatio kutsuu vaaraksi eikä ominaisuudeksi. Ja se kysyi yhtä kolmesta primitiivistä selvittämättä koskaan, että kaksi muuta ovat olemassa.
Ongelma, jonka se ratkaisee, ja analogia, jonka spec itse tekee
Linkki osioon: Ongelma, jonka se ratkaisee, ja analogia, jonka spec itse tekeeEnnen johtoa, laskutoimitus. Sinulla on AI-sovellusta ja asiaa, joihin niiden pitäisi päästä käsiksi — kalenteri, tiketöintijärjestelmä, varastotietokanta, suunnittelutyökalu. Ilman yhteistä sopimusta joku kirjoittaa integraatiota, ja jokainen niistä on skeema plus endpoint plus autentikointitarina plus ylläpitotaakka. Sopimuksen kanssa toolin toimittaja kirjoittaa serverin, sovelluksen toimittaja kirjoittaa clientin, ja kokonaismäärä on .
Tämä ei ole uusi havainto, ja spesifikaatio kertoo, kenen ideasta se on peräisin:
MCP takes some inspiration from the Language Server Protocol, which standardizes how to add support for programming languages across a whole ecosystem of development tools. In a similar way, MCP standardizes how to integrate additional context and tools into the ecosystem of AI applications.1
Ota vertaus kirjaimellisesti, älä kohteliaisuutena. Ennen sitä protokollaa kielen tukeminen editorissa tarkoitti pluginia jokaista editoria kohti; sen jälkeen kielitiimi julkaisi yhden serverin ja jokainen editori sai tuen. Menestyksen mitta ei ollut eleganssi vaan se, että integraatioiden määrä lakkasi kertautumasta. Sama seuraa tästä: arvo on toteutusten määrässä, ei suunnittelussa. Protokolla, jota kaksi tuotetta puhuu, on tietomuoto lisäseremonialla.
Mitä johdolla oikeasti kulkee
Linkki osioon: Mitä johdolla oikeasti kulkeeMCP-viestit ovat JSON-RPC 2.0:aa. Pyyntö on objekti, jossa on jsonrpc, id, method ja valinnainen params; vastaus kantaa saman id-arvon ja joko result- tai error-kentän; notifikaatio on pyyntö ilman id-kenttää eikä saa vastausta. Spesifikaatio lisää päälle kolme rajoitetta: id on oltava merkkijono tai numero eikä se saa olla null, se ei saa törmätä toiseen vielä kesken olevaan pyyntöön, ja jokaisen tuloksen on kannettava resultType-kenttä.2
Stdio-transportissa — siinä, jota yllä oleva komento käytti — kehystyssääntö on yksi rivi per viesti:
Messages are delimited by newlines, and MUST NOT contain embedded newlines. […] The server MUST NOT write anything to its
stdoutthat is not a valid MCP message.3
Tuo viimeinen lause on yleisin tapa, jolla kotitekoinen server hajoaa, ja se hajoaa hiljaa: harhautunut console.log, edistymispalkki, riippuvuuden deprekaatiovaroitus, ja clientin rivijäsennin törmää johonkin, mikä ei ole JSONia. Pakotie on samassa osiossa — server may kirjoittaa mitä haluaa stderr-virtaan, eikä clientin should not tulkita sitä virheeksi. Yllä oleva referenssiserver tulostaa Starting default (STDIO) server... jokaisella käynnistyksellä stderr-virtaan, minkä vuoksi pipe silti toimi.
Toinen standardi transport on Streamable HTTP: jokainen viesti on POST yhteen endpointiin, ja vastaus on joko JSON-objekti tai pyyntöön rajattu Server-Sent Events -virta — wire format, jonka luku 14 jäsensi käsin. Semantiikka on molemmissa sama, koska transport on binding: se määrittää kehystyksen ja toimituksen, ei merkitystä.4
Ensimmäinen väärä asia: versiota ei ollut
Linkki osioon: Ensimmäinen väärä asia: versiota ei ollutYllä oleva komento lähetti tools/list eikä mitään muuta. Nykyisen revision mukaan pyyntö on virheellinen, ja speksiä noudattavan serverin täytyy hylätä se.
2026-07-28 alkaen MCP on tilaton protokolla, ja spesifikaatio sanoo sen kiertelemättä:
The Model Context Protocol (MCP) is a stateless protocol: all the information needed to process a request is contained in the request itself. A server processes each request independently; no state should be inferred from previous requests, even those on the same connection or stream.2
Siksi jokainen pyyntö kantaa oman protokollaversion ja omat client capabilities -tietonsa varatussa _meta-objektissa params-kohdan sisällä. Kaksi näistä kentistä vaaditaan joka ikisessä pyynnössä; pyyntö, josta jompikumpi puuttuu, on virheellinen ja serverin must vastata -32602:2
_meta-avain | pakollinen | mitä se on |
|---|---|---|
io.modelcontextprotocol/protocolVersion | kyllä | revisio, jota tämä pyyntö puhuu, esim. "2026-07-28" |
io.modelcontextprotocol/clientCapabilities | kyllä | mitä client voi tehdä serverille tässä pyynnössä |
io.modelcontextprotocol/clientInfo | ei (mutta should) | clientin nimi ja versio, vain näyttöä ja lokeja varten |
io.modelcontextprotocol/logLevel | ei | vähimmäislokitaso, jota serverin pitäisi lähettää tälle pyynnölle |
Auki kirjoitettuna oikea tools/list näyttää tältä — ja tämä on viimeinen kerta, kun tämä luku näyttää metadatan kokonaan, koska se on tästä lähtien jokaisessa pyynnössä:
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{"elicitation":{"form":{}}},
"io.modelcontextprotocol/clientInfo":{"name":"bare-hands","version":"0.0.1"}}}}Capability-objekti on neuvottelu. Erillistä neuvotteluvaihetta ei enää ole: client ilmoittaa joka pyynnöllä, mitä se voi tehdä, server ilmoittaa tuloksessa, mitä se voi tehdä, eikä kumpikaan osapuoli saa käyttää ominaisuutta, jota toinen ei ole ilmoittanut. Serverin, joka tarvitsee capabilityn, jota client ei ilmoittanut, must vastata -32021 ja nimetä puuttuva capability kentässä data.requiredCapabilities. Serverin, joka ei puhu pyydettyä versiota, must vastata -32022 ja luetella versiot, joita se puhuu.2
Clientit, jotka haluavat vastauksen etukäteen, voivat kysyä sitä: server/discover on pakollinen RPC, joka palauttaa tuetut versiot, capabilities, identiteetin ja valinnaisen instructions-lohkon yhdellä round tripillä.5 Sen kutsuminen on valinnaista. Sen toteuttaminen ei ole.
Toinen väärä asia: server oli legacy
Linkki osioon: Toinen väärä asia: server oli legacyKomento toimi. Nykyisen revision mukaan sen ei olisi pitänyt, ja syy ansaitsee mittauksen eikä kappaletta, koska se on koko ekosysteemin tila yhdellä rivillä.
Probaa referenssiserveriä niin kuin spesifikaatio käskee modernia clientiä probaamaan:
echo '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{}}}}' \
| npx @modelcontextprotocol/server-everything stdio{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}Tämä on yhteensopivuussäännön kolmas haara: DiscoverResult tarkoittaa modernia, tunnistettu moderni virhe tarkoittaa modernia mutta väärää versiota, ja mikä tahansa muu — mukaan lukien -32601 — tarkoittaa legacyä, palaa initialize-handshakeen.3 Tee siis niin ja pyydä nykyistä revisiota:
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-07-28",
"capabilities":{},"clientInfo":{"name":"bare-hands","version":"0.0.1"}}}
← {"result":{"protocolVersion":"2025-11-25","capabilities":{"tools":{"listChanged":true},
"prompts":{"listChanged":true},"resources":{"subscribe":true,"listChanged":true},
"logging":{},"tasks":{…},"completions":{}},"serverInfo":{"name":"mcp-servers/everything",
"title":"Everything Reference Server","version":"2.0.0"},"instructions":"…"}}Client pyysi 2026-07-28 ja server vastasi 2025-11-25. 7. syyskuuta 2026 virallinen referenssiserver — npm-paketti @modelcontextprotocol/server-everything, versio 2026.8.31, julkaistu 31. elokuuta 2026 — ei toteuta nykyistä revisiota. Päivämäärien perusteella ei toteuta myöskään TypeScript SDK, jonka päälle se on rakennettu: julkaisu 1.30.0 tuli ulos 27. heinäkuuta 2026, päivää ennen revisiota.
Lue seuraus, älä juorua. Lähes kaikki MCP:stä kirjoitettu kuvaa protokollaa, jossa on initialize-handshake, sessio, roots/list-pyyntö, jonka server lähettää clientille, ja HTTP+SSE-transport. Kaikki neljä ovat poissa tai poistumassa. Kun luet mitä tahansa MCP:stä, myös tätä sivua, ensimmäinen asia, jota etsiä, on revisionumero.
Ja syy siihen, miksi aivan ensimmäinen komento toimi, on spesifikaatiossa kuvattu vaaraksi eikä ominaisuudeksi:
some legacy servers do not validate that a request arrives after
initializeand would process an era-ambiguous method (such astools/call) under legacy semantics. Probing yields a deterministic failure instead.3
Mitattu: tools/list lähettäminen kyseiselle serverille täysin ilman handshakeä palauttaa koko katalogin. Metodi, joka olisi pitänyt hylätä, palveltiin, ja juuri siksi spesifikaatio käskee probaamaan ensin server/discover-kutsulla, vaikka tukisit vain moderneja versioita.
Kolme roolia ja koko dokumentin lainattava lause
Linkki osioon: Kolme roolia ja koko dokumentin lainattava lauseMCP:ssä on kolme osapuolta, ja ero kahden ensimmäisen välillä on se, jonka ihmiset litistävät:
Host. Sovellus: chat-tuote, editori, agent. Se omistaa keskustelun, mallin, tunnistetiedot ja käyttäjän suostumuksen. Se luo clientit ja valvoo niiden välistä turvarajaa.
Client. Hostin sisäinen connector. Jokainen client puhuu täsmälleen yhdelle serverille — tiukka 1:1-suhde — ja liittää protokollaversion ja capabilities jokaiseen reitittämäänsä pyyntöön.
Server. Prosessi tai palvelu, joka paljastaa resources, tools ja prompts. Se voi olla paikallinen tai etänä, se toimii itsenäisesti, ja sen koko tehtävä on yksi rajattu alue.6
Tuo "täsmälleen yksi server" -sääntö ei ole kirjanpitoa. Se tekee alla olevasta suunnitteluperiaatteesta toteutettavan, ja tämä on lause, joka spesifikaatiosta kannattaa ottaa mukaan, jos otat vain yhden:
Servers should not be able to read the whole conversation, nor "see into" other servers. Servers receive only necessary contextual information. Full conversation history stays with the host. Each server maintains isolation. Cross-server interactions are controlled by the host.6
Se kumoaa mentaalimallin, jonka kanssa useimmat tulevat paikalle. Sääserver, jonka liität assistantisi, ei näe, mitä kysyit. Se näkee tools/call-kutsun ja mallin valitsemat argumentit, eikä mitään muuta — ei aiempia vuoroja, ei system promptiasi, ei tuloksia, jotka kalenteriserver palautti hetkeä aiemmin. Jos kahden serverin täytyy tehdä yhteistyötä, host kantaa arvon yhdeltä toiselle tietoisesti, koska malli pyysi sitä. Siksi eristys on se tietoturvaominaisuus, johon luku 30 nojaa: kompromettoidulla serverillä on pieni, määritelty vaikutusalue, ja sen laajentaminen edellyttää hostin yhteistyötä.
Kolmas asia: kolme primitiiviä järjestettynä sen mukaan, kuka päättää
Linkki osioon: Kolmas asia: kolme primitiiviä järjestettynä sen mukaan, kuka päättääEnsimmäinen komento pyysi serveriltä tools ja sai kolmetoista. Kysy kaksi muuta kysymystä, ja se vastaa niihinkin: resources/list palauttaa seitsemän, prompts/list palauttaa neljä. Mikään niistä ei ilmestynyt, koska mikään ei kysynyt. Tämä tuo meidät MCP:n pedagogiseen selkärankaan, joka istuu spesifikaatiossa taulukkona, jota lähes kukaan ei lainaa:
| Primitiivi | Kontrolli | Kuvaus | Esimerkki |
|---|---|---|---|
| Prompts | Käyttäjän kontrolloima | Interaktiivisia malleja, jotka käynnistyvät käyttäjän valinnasta | Slash-komennot, valikkovalinnat |
| Resources | Sovelluksen kontrolloima | Kontekstuaalista dataa, jonka client liittää ja hallitsee | Tiedostosisällöt, git-historia |
| Tools | Mallin kontrolloima | LLM:lle paljastettuja funktioita toimien tekemiseen | API POST -pyynnöt, tiedostojen kirjoittaminen |
Ei "kolme tapaa paljastaa capability". Vaan kolme vastausta kysymykseen kuka päättää, että tämä tapahtuu. Malli päättää kutsua toolia. Sovellus päättää liittää resourcen. Ihminen päättää ajaa promptin. Jos ymmärrät tämän väärin, ominaisuus toimii silti, mutta se toimii väärällä hetkellä ja väärästä syystä.
Selkeimmin sen tuntee kalenterin kautta. Tässä on server, joka paljastaa saman kalenterin kolmesti, kerran jokaisena primitiivinä, sadalla rivillä tavallista Nodea ilman riippuvuuksia:
const TOOL = {
name: "create_event",
description: "Create a calendar event. Writes to the calendar.",
inputSchema: {
type: "object",
properties: {
title: { type: "string", description: "Event title." },
startsAt: { type: "string", format: "date-time", description: "Start, ISO 8601 UTC." },
},
required: ["title"],
},
};
switch (method) {
case "resources/read":
return ok(id, { contents: [{ uri: "calendar://week",
mimeType: "application/json", text: JSON.stringify(EVENTS) }],
ttlMs: 60000, cacheScope: "private" });
case "prompts/get":
return ok(id, { description: PROMPT.description, messages: [{ role: "user",
content: { type: "text", text: `Read calendar://week and draft a plan. ` +
`Focus: ${params.arguments?.focus ?? "balance"}.` } }] });
case "tools/list":
return ok(id, { tools: [TOOL], ttlMs: 300000, cacheScope: "public" });
}Aja se ja kysy kaikilla kolmella tavalla. Oikea output, yksi viesti per rivi johdolla, tässä sivua varten rivitettynä, pyyntö _meta ja serverin identiteettilohko poistettuina:
→ resources/read {"uri":"calendar://week"}
← {"resultType":"complete","contents":[{"uri":"calendar://week",
"mimeType":"application/json","text":"[{\"id\":\"e1\",\"title\":\"Standup\",
\"startsAt\":\"2026-09-07T09:00:00Z\"},{\"id\":\"e2\",\"title\":\"Design review\",
\"startsAt\":\"2026-09-09T15:00:00Z\"}]"}],"ttlMs":60000,"cacheScope":"private"}
→ prompts/get {"name":"prepare_week","arguments":{"focus":"deep work"}}
← {"resultType":"complete","description":"Read the week and draft a plan.",
"messages":[{"role":"user","content":{"type":"text",
"text":"Read calendar://week and draft a plan. Focus: deep work."}}]}
→ tools/call {"name":"create_event","arguments":{"title":"Dentist",
"startsAt":"2026-09-10T08:30:00Z"}}
← {"resultType":"complete","content":[{"type":"text",
"text":"Created e3: Dentist at 2026-09-10T08:30:00Z"}],
"structuredContent":{"id":"e3","title":"Dentist","startsAt":"2026-09-10T08:30:00Z"},
"isError":false}Kolme metodia, kolme muotoa, yksi kalenteri. Nyt ydinkohta:
Viikon lukeminen on resource
Linkki osioon: Viikon lukeminen on resourceSillä on URI-osoite, se on inertti, ja sovellus päättää, liitetäänkö se keskusteluun. Mikään protokollassa ei anna mallin kurkottaa sitä omin päin. Tulos kantaa ttlMs- ja cacheScope-kentät, jotka ovat uusia tässä revisiossa, jotta client voi cachettaa viikon minuutiksi pollaamisen sijaan.
Tapahtuman luominen on tool
Linkki osioon: Tapahtuman luominen on toolSillä on skeema, sillä on sivuvaikutuksia, ja malli päättää, milloin sitä kutsutaan. Sen tulos kantaa isError-kentän, jota luku 18 perusteli: validointivirhe palaa tool-tuloksena, jonka malli voi lukea ja korjata, ei protokollavirheenä.
"Valmistele viikkoni" on prompt
Linkki osioon: "Valmistele viikkoni" on promptSe on nimetty, argumentteja ottava template, jonka ihminen käynnistää — valikon slash-komento. Se palauttaa viestejä, ei vastausta. Se on tapa, jolla serverin tekijä voi toimittaa muotoilun, joka toimii hänen omien tooliensa kanssa; juuri se on tietoa, joka serverin tekijällä on ja käyttäjällä ei.
Lähes kaikki tekevät näistä kaikista kolmesta tools. Tuloksena on katalogi, jossa luku, jonka sovelluksen olisi pitänyt liittää hiljaa, kilpailee mallin attentionista kirjoituksen kanssa, joka vaatii hyväksynnän, ja jossa asia, jolle ihminen halusi painikkeen, on haudattu skeemaan. Oikein tekeminen ei maksa mitään, ja se päätetään ennen kuin kirjoitat riviäkään.
Server ei voi kutsua sinua
Linkki osioon: Server ei voi kutsua sinuaKalenteritoolilla on yksi pakollinen argumentti, title, ja valinnainen startsAt. Pyydä sitä luomaan tapahtuma ilman päivämäärää, ja takaisin tulee jotain kiinnostavaa:
→ tools/call {"name":"create_event","arguments":{"title":"Dentist"}}
← {"resultType":"input_required",
"inputRequests":{"when":{"method":"elicitation/create","params":{"mode":"form",
"message":"When should \"Dentist\" start?",
"requestedSchema":{"type":"object",
"properties":{"startsAt":{"type":"string","format":"date-time"}},
"required":["startsAt"]}}}},
"requestState":"eyJ0aXRsZSI6IkRlbnRpc3QifQ=="}Server ei lähettänyt pyyntöä. Se vastasi sille annettuun pyyntöön kentällä resultType: "input_required" ja kuvauksella siitä, mitä se vielä tarvitsee. Client kerää vastauksen ihmiseltä ja lähettää sitten alkuperäisen kutsun uudelleen — uudella id-arvolla, kantaen inputResponses-kenttää ja kaiuttaen läpinäkymättömän requestState-arvon takaisin:
→ tools/call {"name":"create_event","arguments":{"title":"Dentist"},
"inputResponses":{"when":{"action":"accept",
"content":{"startsAt":"2026-09-10T08:30:00Z"}}},
"requestState":"eyJ0aXRsZSI6IkRlbnRpc3QifQ=="}
← {"resultType":"complete","content":[{"type":"text",
"text":"Created e3: Dentist at 2026-09-10T08:30:00Z"}],"isError":false}Tämä on Multi Round-Trip Requests, joka tuotiin nykyiseen revisioon, ja se korvasi vanhemman mallin, jossa serverit lähettivät JSON-RPC-pyyntöjä takaisin clienteille. Transport-spesifikaatio sanoo säännön nyt suoraan: "servers do not initiate JSON-RPC requests and clients do not send JSON-RPC responses".4 Aloitteen suunta on yksi, ja se kuuluu hostille.
Kaksi client-puolen ominaisuutta kulkee tämän mekanismin päällä, ja toisella niistä on nimi, joka kompastuttaa.
Elicitation tarkoittaa, että server pyytää ihmiseltä jotain: lomake, jossa on tarkoituksella rajattu JSON Schema — litteitä objekteja, primitiivisiä ominaisuuksia, ei sisäkkäisyyttä — jotta mikä tahansa client voi renderöidä sen ilman layout engineä. Siinä on kova sääntö: serverit must not käyttää lomaketilaa pyytääkseen "passwords, API keys, access tokens, or payment credentials", ja niiden must käyttää niihin URL-tilaa, joka lähettää käyttäjän sivulle, jota client ei koskaan lue.7
Sampling tarkoittaa, että server pyytää hostin mallilta generointia, jotta server voi olla älykäs ilman API-avainta. Ja tässä on sanastovaroitus, koska tämä sana tarkoittaa tässä kurssissa jo jotain muuta: tämä ei ole luvun 17 sampling. Mikään tässä ei liity temperatureen, top-p:hen tai todennäköisyysjakauman muotoon. Se on sisäkkäinen mallikutsu, joka kulkee protokollaa pitkin taaksepäin.
On toinenkin syy olla tarttumatta siihen: tämän revision kohdalla sampling on deprecated, roots- ja logging-ominaisuuksien rinnalla SEP-2577:n alla, ja ehdotettu migraatio on suorasukainen — "integrate directly with LLM provider APIs instead of Sampling".8 Idea ei epäonnistunut teknisesti; se ei onnistunut oikeuttamaan pinta-alaansa, ja protokolla, joka voi poistaa asioita, on terveempi kuin sellainen, joka ei voi.
Riko se tahallasi: yhteydet eivät ole sessioita
Linkki osioon: Riko se tahallasi: yhteydet eivät ole sessioitaTilattomuus kuulostaa wire format -yksityiskohdalta, kunnes testaat sitä. Ota yllä oleva kolmen viestin vaihto ja aja jokainen viesti erillisessä prosessissa — tuore node calendar.mjs, ei jaettua muistia, mitään ei kuljeteta mukana:
process A tools/call (no date) → resultType: input_required
requestState: eyJ0aXRsZSI6IkRlbnRpc3QifQ==
process B tools/call (with the answer, same requestState)
→ resultType: complete
"Created e3: Dentist at 2026-09-10T08:30:00Z"
process C resources/read calendar://week
→ events: 2 (Standup, Design review)Prosessi B, joka ei koskaan nähnyt kysymystä, viimeisteli multi-round-trip-kutsun, jonka prosessi A aloitti. Se on requestState-kentän tarkoitus: jatko kulkee viestissä, joten mikään ei riipu siitä, että prosessi olisi sama.
Prosessi C on epäonnistuminen. Tapahtuma luotiin, eikä sitä ole siellä — koska leluservu pitää EVENTS-arvon moduulitason taulukossa, ja moduulitason taulukko on yhteystilaa. Spesifikaation huomio nimeää virheen täsmällisesti:
an open connection, such as a STDIO process, is not a conversation or session: clients may interleave unrelated requests on the same transport, and a server must not treat connection or process identity as a proxy for conversation or session continuity.2
Määrätty korjaus ei ole sessio. Se on eksplisiittinen handle: luontityökalu palauttaa läpinäkymättömän tunnisteen, ja jokainen myöhempi kutsu ottaa sen tavallisena argumenttina. Protokollalla ei ole siitä mitään käsitettä — "from the wire's perspective a handle is an ordinary string in a tool result and an ordinary argument to subsequent tool calls".9 Tämä laittaa mallin vastuuseen sen kantamisesta ja serverin vastuuseen sen validoimisesta jokaisella kutsulla, että tällä kutsujalla on lupa käyttää sitä, koska handle on nimi eikä käyttöoikeus.
Mitä server maksaa ennen kuin se tekee mitään
Linkki osioon: Mitä server maksaa ennen kuin se tekee mitäänJokainen tool, jonka server paljastaa, on skeema, joka menee promptiisi jokaisella pyynnöllä, ja luku 24 mittasi, mitä se tekee ikkunalle. MCP lisää toisen helposti huomaamatta jäävän rivikohdan, joten molemmat kannattaa laskea yllä olevalta referenssiserveriltä.
13 tool definitions (name + description + inputSchema): 1,307 tokens
cheapest tool, get-tiny-image 52
costliest tool, gzip-file-as-resource 235
server `instructions`, returned by discovery: 312 tokens
------
one server, connected, before it is used: 1,619 tokensKaksi havaintoa. Ensimmäinen on aritmetiikkaa: liitä viisi tämän kokoista serveriä, ja noin kahdeksan tuhatta tokenia ikkunastasi on varattuna joka vuorolla, ikuisesti, riippumatta siitä käyttääkö malli niistä yhtäkään — tämä on mekanismi luvussa 24 lainatun 150 000:sta 2 000:een -vähennyksen takana ja syy siihen, miksi just-in-time tool discovery on olemassa.
Toinen on tietoturvahuomio kirjanpitoasuun pukeutuneena. instructions on luonnollisen kielen tekstiä, jonka serverin tekijä on kirjoittanut ja joka päätyy hostin promptiin, ja vieressä olevat tool-kuvaukset ovat samaa. Spesifikaatio sanoo omissa security principles -kohdissaan, mitä sille tehdään: tool annotations ja descriptions "should be considered untrusted, unless obtained from a trusted server", ja hostien "must obtain explicit user consent before invoking any tool".1 MCP serverin liittäminen ei ole riippuvuuden lisäämistä. Se on sitä, että annat vieraalle 1 619 tokenia system promptistasi ja oikeuden tulla kutsutuksi. Luku 30 kertoo, mitä tapahtuu, kun tuo vieras on vihamielinen.
Päivätty osio: 2026-07-28-revisio ja mitä se rikkoo
Linkki osioon: Päivätty osio: 2026-07-28-revisio ja mitä se rikkooKaikki tässä osiossa pitää paikkansa protokollarevisiosta 2026-07-28, nykyisestä revisiosta, luettuna 7. syyskuuta 2026. Revisiopäivämäärät ovat muodossa YYYY-MM-DD, ja päivämäärä on viimeinen hetki, jolloin taaksepäin yhteensopimaton muutos tehtiin.10 Normatiivinen dokumentti on TypeScript-tiedosto, schema/2026-07-28/schema.ts; sen vieressä oleva JSON Schema generoidaan siitä, minkä vuoksi spesifikaatiota luetaan tässä TypeScriptinä ja miksi MCP:n opettaminen mistä tahansa muusta on käännöksen opettamista.
| Mikä muuttui | Oli | On nyt | Rikkoo |
|---|---|---|---|
| Handshake | initialize + notifications/initialized, kerran per yhteys | poistettu; jokainen pyyntö kantaa _meta-version ja capabilities | jokaisen ennen tätä revisiota kirjoitetun clientin |
| Sessiot | Mcp-Session-Id-header, yhteyskohtainen tila | poistettu; tila kulkee eksplisiittisissä, serverin minttaamissa handles | list-endpointit, jotka vaihtelivat yhteyden mukaan |
| Discovery | pääteltiin initialize-tuloksesta | server/discover, joka serverien must toteuttaa | ei mitään, mutta toteutus on nyt pakollinen |
| Serveriltä clientille -kutsut | server lähetti roots/list, sampling/createMessage, elicitation/create | InputRequiredResult ja clientin retry | jokaisen serverin, joka työnsi pyynnön clientille |
| Tuloksen muoto | mikä tahansa objekti | pakollinen resultType: "complete" tai "input_required" | ei mitään: puuttuva kenttä on luettava arvona "complete" |
| Subscriptions | HTTP GET -virta, resources/subscribe | yksi subscriptions/listen-virta opt-in-tyypeillä | GET-endpoint on poissa |
| Stream resumption | Last-Event-ID-replay Streamable HTTP:ssä | poistettu; katkennut stream kadottaa pyynnön, lähetä uudelleen uudella id-arvolla | clientit, jotka luottivat uudelleentoimitukseen |
| Roots | client-ominaisuus, jota serverit saattoivat pyytää | deprecated (SEP-2577); välitä polut tool-argumentteina tai resource URI:na | ei vielä mitään — kahdentoista kuukauden ikkuna |
| Sampling ja logging | client-ominaisuuksia | deprecated (SEP-2577) | ei vielä mitään — kahdentoista kuukauden ikkuna |
| HTTP+SSE-transport | deprecated alkaen 2025-03-26 | Deprecated elinkaarikäytännön alla (SEP-2596) | migroi Streamable HTTP:hen |
| Client registration | OAuth 2.0 Dynamic Client Registration, RFC 7591 | deprecated Client ID Metadata Documents -mallin hyväksi | säilytetty authorization servereille, joilla niitä ei ole |
| Virhekoodit | -32002 kun resourcea ei löytynyt | -32602; -32020–-32099 varattu specille | uudet koodit -32020, -32021, -32022 |
Tuon taulukon alla oleva hallintomuutos on tärkeämpi kuin yksikään rivi. Tämä revisio otti käyttöön feature lifecycle and deprecation policy -käytännön: ominaisuudet ovat Active, Deprecated tai Removed, deprecated-ominaisuus dokumentoi migraatiopolkunsa ja pysyy spesifikaatiossa vähintään kaksitoista kuukautta ennen kuin siitä tulee poistokelpoinen, ja rekisteri luettelee kaiken, mikä on tällä hetkellä Deprecated-tilassa.8 Ennen tuota käytäntöä "deprecated" AI-protokollassa tarkoitti sitä, mitä viimeisin blogipostaus sattui sanomaan. Nyt se tarkoittaa päivämäärää.
Näytä lisätiedot
Extensions, joista kukaan ei ole vielä kirjoittanut.
Ytimen lisäksi MCP määrittää valinnaisia extensions — "always opt-in and require explicit support from both client and server", jotka ilmoitetaan clientin ja serverin capabilities-kentän extensions-kentän kautta.1 Kolme kannattaa tuntea nimeltä:
- Tasks (
io.modelcontextprotocol/tasks), siirrettiin ytimestä viralliseksi extensioniksi tässä revisiossa: pitkään kestävien operaatioiden asynkroninen suoritus, pollingtasks/get-kutsulla, kesken ajon annettava syötetasks/update-kutsulla ja kestävät handles. Se on vastaus tooliin, joka kestää kaksikymmentä minuuttia, minkä luku 23 hoiti progress-tapahtumalla ja signaalilla, joka yltää tooliin. - Skills over MCP, työryhmä, joka tekee agent skills — luvun 28 aiheen — löydettäviksi ja kulutettaviksi protokollan kautta.
- MCP Apps, keskusteluun inline-renderöity interaktiivinen UI: kaaviot, lomakkeet, videosoittimet.
Ja huomaa, mitä "negotiated" nyt tarkoittaa: ei ole initialization-vaihetta, jossa neuvotella, joten extension ilmoitetaan per pyyntö kuten kaikki muukin.
Missä MCP sijaitsee suhteessa kaikkeen, mihin se sekoitetaan
Linkki osioon: Missä MCP sijaitsee suhteessa kaikkeen, mihin se sekoitetaanTässä on koko lohkon sanasto yhdessä paikassa.
| Mitä se on | Kuka puhuu kenelle | Milloin se on vastaus | |
|---|---|---|---|
| Tavallinen API | Rajapinta ohjelmalle | koodisi ↔ palvelu | Kirjoitat kutsujan. Hallitset skeemaa, authia ja virheenkäsittelyä, eikä discovery-ongelmaa ole ratkaistavana. |
| MCP | Protokolla tools-, data- ja template-ominaisuuksien paljastamiseen AI-sovellukselle | host ↔ server, yksi client kumpaankin | Joku muu kirjoitti capabilityn, ja monen hostin pitäisi voida käyttää sitä ilman räätälöityä integraatiota. |
| RAG | Tekniikka tekstin löytämiseen ja promptiin laittamiseen | koodisi ↔ indeksisi | Mallin täytyy tietää jotain. Luku 19. MCP on tapa toimittaa retriever; se ei ole retriever. |
| Agent skills | Kansio, jossa on SKILL.md, jonka malli lukee | malli ↔ dokumentti | Tieto on proseduraalista — miten me teemme tämän — ja se on proosaa, ei funktio. Luku 28. |
| A2A | Protokolla, jolla agents tekevät yhteistyötä vertaisina | agent ↔ agent | Toinen puoli päättelee, suunnittelee ja pitää tilaa pitkän tehtävän yli sen sijaan, että vastaisi kutsuun. |
| ACP | Oli erillinen agent-viestintäprotokolla | — | Se ei ole enää elävä vertailukohta. Katso alta. |
Kaksi näistä ansaitsee kumpikin yhden lauseen, koska juuri niissä sekaannus oikeasti elää.
MCP suhteessa A2A:han ei ole kilpailuasetelma, ja molemmat spesifikaatiot sanovat niin. A2A-dokumentaatio vetää rajan sen mukaan, mitä toisessa päässä on: MCP "defines how an AI agent interacts with and utilizes individual tools and resources, such as a database or an API", jossa tool suorittaa "specific, often stateless, functions"; A2A käsittelee agents, "more autonomous systems", jotka "reason, plan, use multiple tools, maintain state over longer interactions, and engage in complex, often multi-turn dialogues". Sen oma tiivistelmä on muistettava lause: "A2A is about agents partnering on tasks, while MCP is more about agents using capabilities."11 Nämä kaksi asettuvat sisäkkäin — sovellus käyttää A2A:ta tavoittaakseen muita agents, ja jokainen agent käyttää MCP:tä tavoittaakseen omat tools. Luku 25 veti tuon rajan yhden prosessin sisällä, sub-agentilta kysymisen ja keskustelun sille luovuttamisen väliin; A2A vetää sen organisaatioiden väliin.
MCP suhteessa ACP:hen on vertailu vanhentuneeseen premissiin, ja juuri siksi siihen kannattaa vastata. Agent Communication Protocol oli erillinen avoin standardi agent-to-agent-viestintään. Sen oma dokumentaatio alkaa nyt ilmoituksella: "ACP is now part of A2A under the Linux Foundation!"12 Rehellinen vastaus kysymykseen "MCP vai ACP?" syyskuussa 2026 on, että kysymyksessä on yksi vaihtoehto vähemmän kuin sitä varten rankkaavat sivut antavat ymmärtää.
Ja vertailu, jota ihmiset kysyvät eniten, mcp vs api, sisältää vähiten kiinnostavan vastauksen: MCP on API. Se, mitä se lisää, ei ole voimaa vaan konventioita — kiinteä joukko metodinimiä, discovery-kutsu, primitiivien kontrollihierarkia ja eristysmalli. Luovut vapaudesta suunnitella oman rajapintasi ja saat jokaisen hostin, joka puhuu protokollaa; se on vaihtokauppa, jota jokainen protokolla on aina tarjonnut.
Minne tästä mennään seuraavaksi
Linkki osioon: Minne tästä mennään seuraavaksiOsaat nyt lukea spesifikaatiota ilman tulkkia, erottaa resourcen toolista ja promptista sen perusteella, kuka sitä hallitsee, kirjoittaa pyynnön käsin, kun client-kirjasto valehtelee sinulle, ja päivätä minkä tahansa lukemasi MCP-artikkelin sen mukaan, mitä deprecated-ominaisuuksia se yhä opettaa nykyisinä.
Et ole vielä julkaissut sellaista. Luku 27 kirjoittaa saman serverin kahdesti — TypeScriptillä ja Pythonilla rinnakkain, koska MCP on tämän kurssin ainoa aidosti kaksikielinen alue ja numerot sanovat niin molempiin suuntiin. Se käsittelee kaksi elävää transportia kunnolla, inspectorin, paketoinnin ja sen protokollan puolikkaan, jonka tämä luku jätti tahallaan rauhaan: authorization. Koska sillä hetkellä, kun serverisi on etänä eikä aliprosessi omalla kannettavallasi, vieraan client esittää tokenin, ja spesifikaation sääntö siitä, mitä saat sillä tehdä, on epätavallisen tiukka.
Tämä nostaa kysymyksen, johon seuraavan luvun täytyy vastata, eikä se ole ystävällinen: jos token saapuu serverillesi ja se on myönnetty jonkun muun audiencelle, mikä tarkalleen estää sinua välittämästä sitä eteenpäin?
Lähteet ja menetelmä
Linkki osioon: Lähteet ja menetelmäJokainen lainaus, metodinimi, virhekoodi ja sääntö tässä luvussa luettiin Model Context Protocol -spesifikaatiosta, revisio 2026-07-28, 7. syyskuuta 2026. Jokainen trace tuotettiin paikallisesti Node 22:lla: lelukalenteriserver on 101 riviä ilman riippuvuuksia, ja referenssiserver on alla nimetty julkaistu npm-paketti. Mitään maksullista APIa ei kutsuttu tämän luvun kirjoittamiseen — mikään tässä ei tarvitse mallia, mikä on itsessään pointti.
Mittaukset: @modelcontextprotocol/server-everything@2026.8.31, julkaistu 31. elokuuta 2026, rakennettu paketin @modelcontextprotocol/sdk@1.30.0 päälle, julkaistu 27. heinäkuuta 2026 — päivää ennen tämän luvun kuvaamaa revisiota. Se vastaa server/discover-kutsuun arvolla -32601, neuvottelee 2025-11-25, kun pyydetään 2026-07-28, ja palvelee tools/list ilman handshakeä lainkaan. Sen katalogi on 13 tools 7 663 tavussa; token-määrät ovat o200k_base via tiktoken, jokaisen määritelmän name-, description- ja inputSchema-kenttien yli, mikä on se, mitä provider renderöi promptiisi eikä se, mitä JSON-RPC-kehys painaa.
Anthropic, Code execution with MCP: building more efficient agents, 4. marraskuuta 2025, on 150 000:sta 2 000:een -luvun lähde; se lainattiin ja sitä käytettiin luvussa 24, ja siihen vain viitataan tässä.
Viitteet
Linkki osioon: Viitteet-
Specification,
modelcontextprotocol.io/specification/latest(uudelleenohjaa kohteeseen/2026-07-28), luettu 7. syyskuuta 2026. Lähde Language Server Protocol -vertaukselle; väitteelle, että spesifikaatio "based on the TypeScript schema inschema.ts"; base-protocol-yhteenvedolle ("Stateless, self-contained requests", "Per-request capability negotiation"); extension-listalle (Tasks, Skills over MCP, MCP Apps) ja väitteelle, että extensions "are always opt-in and require explicit support from both client and server"; sekä Security and Trust & Safety -periaatteille, mukaan lukien "Hosts must obtain explicit user consent before invoking any tool" ja tool annotations -sisällön käsittely epäluotettavana. ↩ ↩2 ↩3 -
Base Protocol,
modelcontextprotocol.io/specification/2026-07-28/basic. Lähde JSON-RPC-rajoitteille (ei-null id, ei id:n uudelleenkäyttöä, pakollinenresultType); Statelessness-osiolle ja sen huomiolle, ettei avoin stdio-prosessi ole sessio; varattujen_meta-avainten taulukolle ja jokaisen pyyntökohtaisen kentän pakolliselle/valinnaiselle tilalle;-32602-säännölle puuttuvasta pakollisesta kentästä;MissingRequiredClientCapability(-32021) -säännölle; sekä virhekoodien allokointikäytännölle. ↩ ↩2 ↩3 ↩4 ↩5 -
stdio transport,
modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio. Lähde newline-delimited-kehystyssäännöille,stdout-puhtausvaatimukselle,stderr-sallinnalle ja kolmen lopputuloksen taaksepäin yhteensopivuusprobelle — mukaan lukien varoitus, että jotkin legacy-serverit käsittelevät aikakausiepäselviä metodeja ilman handshakeä, minkä tämän luvun mittaus toistaa. ↩ ↩2 ↩3 -
Transports overview,
modelcontextprotocol.io/specification/2026-07-28/basic/transports. Lähde "a transport is a binding" -kehystykselle ja väitteelle, että serverit eivät aloita JSON-RPC-pyyntöjä eivätkä clientit lähetä JSON-RPC-vastauksia. ↩ ↩2 -
Discovery,
modelcontextprotocol.io/specification/2026-07-28/server/discover. Lähdeserver/discover-kutsun pakollisuudelle,DiscoverResult-muodolle jainstructions-kentälle, jota kuvataan "optional natural-language guidance for LLMs on how to use this server effectively". ↩ -
Architecture,
modelcontextprotocol.io/specification/2026-07-28/architecture. Lähde host/client/server-määritelmille, 1:1 client-to-server -säännölle, neljälle suunnitteluperiaatteelle, joista eristysperiaate lainataan tässä ilman viidettä luetelmakohtaansa, "Host process enforces security boundaries", sekä capability-neuvottelun osiolle. ↩ ↩2 -
Elicitation,
.../client/elicitation, ja Sampling,.../client/sampling. Lähde kahdelle elicitation-tilalle ja niiden rajatulle skeemalle; kiellolle pyytää tunnistetietoja lomaketilan kautta; sampling-määritelmälle, sen human-in-the-loop-vaatimukselle ja siihen liitetylle deprekaatiovaroitukselle. ↩ -
Key Changes,
modelcontextprotocol.io/specification/2026-07-28/changelog, ja Feature lifecycle and deprecation policy,.../community/feature-lifecycle. Lähde jokaiselle muutostaulukon riville: sessioiden jaMcp-Session-Id-headerin poisto (SEP-2567); tilattomuus jainitialize-poisto (SEP-2575);server/discover(SEP-2575);subscriptions/listen(SEP-2575); Multi Round-Trip Requests jaresultType(SEP-2322); stream resumability -ominaisuuden poisto (SEP-2575); Roots-, Sampling- ja Logging-ominaisuuksien deprekaatio (SEP-2577); HTTP+SSE:n uudelleenluokittelu (SEP-2596); Dynamic Client Registration -ominaisuuden deprekaatio Client ID Metadata Documents -mallin hyväksi; virhekoodien uudelleennumerointi; sekä kahdentoista kuukauden deprekaatioikkuna. ↩ ↩2 -
Tools,
modelcontextprotocol.io/specification/2026-07-28/server/tools, ja Server Features,.../server. Lähde yllä toistetulle kontrollihierarkiataulukolle;tools/list- jatools/call-muodoille;isError-erolle protokollavirheiden ja tool-suoritusvirheiden välillä; tool-nimisäännöille ja namespace-huomiolle, joka suosittelee "prefixing tool names with a server identifier"; sekä ei-normatiiviselle "Stateful Tools" -ohjeelle eksplisiittisistä handles. ↩ -
Versioning,
modelcontextprotocol.io/specification/versioning. LähdeYYYY-MM-DD-skeemalle, Draft/Current/Final-revisiotiloille, vahvistukselle, että 2026-07-28 on current, sekä pyyntökohtaisille neuvottelusäännöille. SDK-tasotaulukko osoitteessamodelcontextprotocol.io/docs/sdklistaa TypeScriptin, Pythonin, C#:n, Go:n ja Rustin Tier 1 -tasolle, Javan ja Rubyn Tier 2 -tasolle sekä Swiftin, PHP:n ja Kotlinin Tier 3 -tasolle. ↩ -
A2A Protocol, versio 1.0.0,
a2a-protocol.org— spesifikaatio ja sivu A2A and MCP: Relationship and Distinction, luettu 7. syyskuuta 2026. Lähde tools-versus-agents-erottelulle, väitteelle, että nämä kaksi protokollaa "address distinct but highly complementary needs", sekä partnering/using-muotoilulle. ↩ -
Agent Communication Protocol,
agentcommunicationprotocol.dev, luettu 7. syyskuuta 2026: "ACP is now part of A2A under the Linux Foundation!", banneri, joka lisättiin spesifikaation yläpuolelle, vaikka spesifikaatio palvellaan yhä kokonaisena — architecture, agent manifest, agent discovery, message structure, stateful agents, run lifecycle ja REST-endpoint-lista vastaavat kaikki edelleen 200. Spesifikaatio ei kadonnut; projekti katosi. ↩