Model Context Protocol (MCP) 2026: Käytännön opas oman palvelimen rakentamiseen

Rakenna tuotantokelpoinen MCP-palvelin TypeScriptillä ja Pythonilla. Käytännön esimerkit Claude Desktop -integroinnista, Streamable HTTP -kuljetuksesta ja OAuth 2.1 -autentikoinnista, plus selkeä turvallisuusmalli.

MCP-palvelin TypeScriptillä: Opas 2026

Päivitetty: 1. kesäkuuta 2026

Model Context Protocol (MCP) on Anthropicin vuonna 2024 julkaisema avoin standardi, joka liittää kielimallit turvallisesti ulkoisiin tietolähteisiin ja työkaluihin yhtenäisellä JSON-RPC-rajapinnalla. Käytännössä MCP korvaa erilliset, sirpaleiset integraatiot yhdellä protokollalla. Rakennat yhden palvelimen, ja jokainen MCP-yhteensopiva asiakas (Claude Desktop, Cursor, Zed, Windsurf ja kymmenet muut) pystyy käyttämään sitä ilman lisäkoodia. Tässä oppaassa rakennetaan tuotantokelpoinen MCP-palvelin TypeScriptillä, käydään läpi suojausmalli ja näytetään miten se eroaa perinteisestä funktiokutsusta.

  • MCP on JSON-RPC 2.0 -pohjainen avoin protokolla, joka standardoi LLM-sovellusten yhteyden työkaluihin, tietolähteisiin ja kehotteisiin.
  • Protokollan kolme primitiiviä (tools, resources ja prompts) kattavat suurimman osan agenttisovellusten tarpeista.
  • Vuoden 2025 lopun spesifikaatiossa Streamable HTTP -kuljetus korvasi vanhan HTTP+SSE-mallin ja toi mukanaan OAuth 2.1 -autentikoinnin.
  • Oma palvelin syntyy noin 50 koodirivissä virallisilla TypeScript- tai Python-SDK:illa.
  • MCP:n ekosysteemi sisältää yli 5 000 julkista palvelinta (kesäkuu 2026), kattaen kaiken Postgresista GitHubiin ja Figmaan.
  • Turvallisuus rakentuu nimenomaisten käyttöoikeuksien, sandbox-ajon ja käyttäjän suostumuksen päälle. Palvelimeen ei luoteta oletuksena.

Mikä on Model Context Protocol?

Model Context Protocol on Anthropicin marraskuussa 2024 julkaisema, sittemmin avoimena standardina kehitetty protokolla, joka määrittelee miten LLM-sovellukset (asiakkaat) keskustelevat ulkoisten datalähteiden ja työkalujen (palvelimien) kanssa. Protokolla rakentuu JSON-RPC 2.0 -spesifikaation päälle ja määrittää selkeät viestityypit kättelylle, työkalukutsuille, resurssien lukemiselle ja kehotteiden hakemiselle.

Ennen MCP:tä jokainen tekoälyalusta toteutti omat integraationsa. ChatGPT:llä oli pluginit, Cursorilla omat työkalut, Continue.dev käytti omaa formaattiaan. Tuloksena oli klassinen M×N-ongelma, jossa N asiakasta tarvitsi M integraatiota, eli M×N erillistä toteutusta. MCP muuttaa tämän M+N:ksi. Kirjoitat palvelimen kerran, ja kaikki yhteensopivat asiakkaat saavat sen käyttöön.

Kesäkuuhun 2026 mennessä spesifikaatiosta on julkaistu kolme suurta versiota. Viimeisimmässä (versio 2025-06-18) tärkeimmät muutokset ovat Streamable HTTP -kuljetus, OAuth 2.1 -tuki, jäsennellyt työkalutulokset ja "elicitation"-mekanismi, joka mahdollistaa palvelimen pyytää lisätietoja käyttäjältä kesken työnkulun. Virallinen spesifikaatio on luettavissa osoitteessa modelcontextprotocol.io.

Miten MCP eroaa funktiokutsuista?

Tämä on yleisin kysymys, jonka kuulen kun esittelen MCP:tä kollegoille. Funktiokutsut (function calling, tool use) ovat mallitason ominaisuus. Kerrot kielimallille, millaisia työkaluja on saatavilla, ja se päättää milloin niitä kutsua. MCP toimii eri kerroksessa. Se on protokolla, joka kuljettaa noita funktiomäärittelyjä ja niiden tuloksia asiakkaan ja palvelimen välillä.

OminaisuusFunktiokutsut (raaka)Model Context Protocol
TasoMallirajapinta (OpenAI, Anthropic API)Sovelluskerroksen protokolla
UudelleenkäytettävyysSidottu yhteen sovellukseenSama palvelin toimii kaikissa MCP-asiakkaissa
LöydettävyysManuaalinen rekisteröinti koodiinDynaaminen tools/list-kysely
TilallisuusTilatonTukee tilallisia istuntoja ja ilmoituksia
ResurssitEi käsitettäURI-pohjaiset resurssit erillinen primitiivi
KuljetusHTTP-kutsu API:inSTDIO, Streamable HTTP, WebSocket
AutentikointiAPI-avain otsikossaOAuth 2.1 + Resource Indicators

Käytännön ero on tämä. Kun rakennat funktiokutsuilla agentin, joka lukee GitHubista issueita, joudut toistamaan saman koodin jokaisessa sovelluksessasi. MCP:llä rakennat github-mcp-server:n kerran, ja sekä Claude Desktop että oma CLI-agenttisi voivat käyttää sitä. Sisäisesti MCP-asiakas muuntaa palvelimen ilmoittamat työkalut mallitason funktiokutsumäärittelyiksi. Protokolla on siis funktiokutsujen päällä, ei niiden korvaaja.

MCP-arkkitehtuuri ja primitiivit

MCP-järjestelmässä on kolme roolia: isäntä (host, esim. Claude Desktop -sovellus), asiakas (client, isännän sisällä elävä yhteyskäytävä) ja palvelin (server, ulkoinen prosessi joka tarjoaa kykyjä). Yksi isäntä voi pitää useaa asiakas-palvelin-yhteyttä yhtä aikaa, ja jokainen yhteys neuvottelee oman versionsa ja kykynsä kättelyn aikana.

Palvelin voi paljastaa kolme primitiiviä:

  • Tools. Toimintoja, joita malli kutsuu (esim. send_email, query_database). Mallin ohjaamia, sivuvaikutuksia sallittu.
  • Resources. Luettavaa dataa URI:n takana (esim. file://docs/api.md tai postgres://schema/users). Asiakkaan tai käyttäjän valitsemia.
  • Prompts. Uudelleenkäytettäviä kehotemalleja, joita käyttäjä voi vetää slash-komentona.

Vastaavasti asiakas voi tarjota palvelimelle sampling-primitiivin (palvelin saa pyytää LLM-täydennyksiä asiakkaalta), roots-primitiivin (tiedostojärjestelmäjuuret) ja elicitation-primitiivin (palvelin pyytää käyttäjältä lisätietoja). Tämä symmetria mahdollistaa monimutkaisemmat agenttityönkulut, joita on syvennetty myös moniagenttiorkestroinnin käytännön oppaassa.

Rakenna ensimmäinen MCP-palvelin TypeScriptillä

Rakennetaan yksinkertainen palvelin, joka tarjoaa kaksi työkalua: säätietojen haun ja matemaattisen lausekkeen arvioinnin. Käytän tässä virallista @modelcontextprotocol/sdk-pakettia (versio 1.12.x kesäkuussa 2026). Asenna riippuvuudet:

npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx

Luo src/server.ts:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "esimerkki-palvelin",
  version: "1.0.0",
});

server.tool(
  "hae_saa",
  "Palauttaa annetun kaupungin sään lyhyenä kuvauksena.",
  { kaupunki: z.string().describe("Kaupungin nimi suomeksi") },
  async ({ kaupunki }) => {
    const res = await fetch(
      `https://wttr.in/${encodeURIComponent(kaupunki)}?format=3&lang=fi`,
    );
    const teksti = await res.text();
    return {
      content: [{ type: "text", text: teksti.trim() }],
    };
  },
);

server.tool(
  "laske",
  "Arvioi matemaattisen lausekkeen turvallisesti.",
  { lauseke: z.string().describe("Esim. '2 * (3 + 4)'") },
  async ({ lauseke }) => {
    if (!/^[\d\s+\-*/().]+$/.test(lauseke)) {
      return {
        isError: true,
        content: [{ type: "text", text: "Vain numerot ja +-*/() sallittu." }],
      };
    }
    const tulos = Function(`"use strict"; return (${lauseke});`)();
    return { content: [{ type: "text", text: String(tulos) }] };
  },
);

const transport = new StdioServerTransport();
await server.connect(transport);

Käännä ja aja palvelin komennolla npx tsx src/server.ts. Palvelin odottaa nyt JSON-RPC-viestejä standardisyötteestä. Voit testata sen MCP Inspector -työkalulla (npx @modelcontextprotocol/inspector npx tsx src/server.ts), joka avaa selaimeen graafisen käyttöliittymän kättelyä, työkalulistausta ja kutsuja varten. Inspector säästi minulta tunteja, kun ensimmäisen palvelimen kättely meni rikki harmittomalta näyttävän tyyppivirheen takia.

Liitä palvelin Claude Desktopiin

Claude Desktop oli ensimmäinen tuotantotason MCP-asiakas, ja se on yhä helpoin tapa nähdä palvelimesi käytössä. Avaa Claude Desktopin asetustiedosto:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Lisää palvelimesi mcpServers-lohkoon:

{
  "mcpServers": {
    "esimerkki": {
      "command": "npx",
      "args": ["tsx", "/absoluuttinen/polku/src/server.ts"],
      "env": {}
    }
  }
}

Käynnistä Claude Desktop uudelleen. Chat-näkymän alalaidassa näkyy nyt työkalukuvake, ja työkalut hae_saa ja laske ovat käytettävissä. Kun pyydät Claudea hakemaan Helsingin sään, se pyytää suostumusta ja kutsuu sitten palvelinta. Sama palvelin toimii myös Cursorissa, Zedissä ja Continue.devissä ilman muutoksia.

Python-toteutus tietokantakyselyihin

Käytännön työssä monet palvelimet kysyvät tietokannasta. Tässä Python-esimerkki, joka tarjoaa resources-primitiivin Postgres-skeemaan ja tool-primitiivin parametroituun kyselyyn. Vaatii virallisen mcp-paketin (Python-SDK).

from mcp.server.fastmcp import FastMCP
import asyncpg, os

mcp = FastMCP("postgres-palvelin")
DSN = os.environ["DATABASE_URL"]

@mcp.resource("postgres://schema/{taulu}")
async def hae_skeema(taulu: str) -> str:
    """Palauttaa annetun taulun sarakkeet ja tyypit."""
    pool = await asyncpg.create_pool(DSN)
    rivit = await pool.fetch(
        """SELECT column_name, data_type FROM information_schema.columns
           WHERE table_name = $1""",
        taulu,
    )
    await pool.close()
    return "\n".join(f"{r['column_name']}: {r['data_type']}" for r in rivit)

@mcp.tool()
async def kysy(sql: str, parametrit: list[str] | None = None) -> str:
    """Suorittaa vain-luku SQL-kyselyn. Vain SELECT sallittu."""
    if not sql.strip().lower().startswith("select"):
        return "Virhe: vain SELECT-kyselyt ovat sallittuja."
    pool = await asyncpg.create_pool(DSN)
    try:
        rivit = await pool.fetch(sql, *(parametrit or []))
        return "\n".join(str(dict(r)) for r in rivit[:50])
    finally:
        await pool.close()

if __name__ == "__main__":
    mcp.run()

Tämä malli, jossa resources hoitaa skeeman lukemisen ja tool kyselyt, pakottaa mallin tutustumaan rakenteeseen ennen kyselyn rakentamista. Sen myötä onnistumisprosentti nousee selvästi. Sama periaate toimii myös vektoritietokantojen kanssa. Käytännön työnkulut on käyty läpi tuotantovalmiin RAG-pipelinen oppaassa.

Streamable HTTP ja etäpalvelimet

STDIO-kuljetus on oivallinen paikallisille työkaluille, mutta etäpalvelimia varten tarvitaan HTTP. Vuoden 2025 spesifikaatiopäivitys korvasi vanhan HTTP+SSE-mallin Streamable HTTP:lla, jossa yksi /mcp-päätepiste käsittelee sekä asiakkaan POST-pyynnöt että palvelimen ilmoitukset SSE-virtana. Tämä yksinkertaistaa kuormantasausta ja palautumista verkkovirheistä.

import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport }
  from "@modelcontextprotocol/sdk/server/streamableHttp.js";

const app = express();
app.use(express.json());

const server = new McpServer({ name: "etakuljetus", version: "1.0.0" });
// rekisteröi työkalut kuten aiemmin...

const transport = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => crypto.randomUUID(),
});
await server.connect(transport);

app.post("/mcp", (req, res) => transport.handleRequest(req, res, req.body));
app.get("/mcp", (req, res) => transport.handleRequest(req, res));
app.listen(3000);

Etäpalvelimet vaativat lähes aina autentikointia. MCP-spesifikaatio nojaa OAuth 2.1 Resource Indicators -RFC:hen (RFC 8707) ja edellyttää, että asiakas hakee tokenin Authorization Code Flow + PKCE -mekanismilla. Token sidotaan tiettyyn resurssitunnisteeseen, jotta vuotanutta tokenia ei voi käyttää muissa MCP-palvelimissa.

Onko MCP turvallinen?

Protokolla itsessään on turvallinen, mutta vastuu jakautuu kolmeen kerrokseen. Ensinnäkin isäntä (esim. Claude Desktop) pyytää käyttäjältä nimenomaisen suostumuksen jokaiselle työkalukutsulle ensimmäisellä kerralla. Käyttäjä päättää, mitä pääsyä malli saa. Toiseksi palvelimen tekijä validoi syötteet, ajaa pienimmillä mahdollisilla oikeuksilla ja eristää sivuvaikutukset (vain-luku oletuksena, kirjoitusoikeudet erikseen). Kolmanneksi asiakkaan ekosysteemi hallinnoi tokeneita, sandbox-prosesseja ja telemetriaa.

Aiheesta on tehty syvällistä turvallisuustutkimusta, jota voit lukea MCP:n virallisesta turvallisuusoppaasta. Suosittelen myös rakentamaan agenttitason testit, joiden ajoa olemme käsitelleet LLM-arvioinnin oppaassa. Älä luota siihen, että käsin tehty manuaalinen tarkistus löytää regressiot, koska se ei niitä löydä.

MCP tuotannossa: lokitus, virheet ja versiointi

Kun palvelin siirtyy paikallisesta leikkikalusta tiimin tai asiakkaiden käyttöön, kolme asiaa nousee ratkaisevaksi.

Strukturoitu lokitus

Älä kirjoita lokia stdout:iin STDIO-palvelimessa, koska se sotkee protokollan. Käytä erillistä virtaa (stderr tai tiedostoa) ja kirjoita JSON-rivit, jotka sisältävät session_id, tool_name, kestoajat ja virhekoodit. Hyödynnä observability-pinosta kuten Langfuse tai OpenTelemetry-yhteensopiva tracing-järjestelmä, johon voit liittää MCP-spesifiset span-attribuutit.

Virhekoodit ja jäsennellyt tulokset

Uudessa spesifikaatiossa työkalu voi palauttaa structuredContent-kentän, jossa on koneellisesti tulkittava JSON-objekti. Käytä sitä aina kun mahdollista. Malli osaa lukea siitä luotettavammin kuin vapaasta tekstistä, ja CI-testit voivat vertailla rakenteita suoraan. Aseta virhetilanteessa isError: true ja anna selittävä viesti, mutta älä paljasta sisäisiä toteutustietoja (stacktrace, salasanat, polut).

Versiointi ja yhteensopivuus

Asiakkaat ilmoittavat tuetun protokollaversion kättelyssä. Jos lisäät rikkovan muutoksen (esim. pakollinen parametri olemassa olevaan työkaluun), nosta palvelimesi nameiä tai julkaise erillinen v2-palvelin. Älä yritä piilottaa muutoksia. Käyttäjäkokemus huononee nopeasti, kun työkalut alkavat virheillä ilman selitystä.

Usein kysytyt kysymykset

Korvaako MCP OpenAI:n funktiokutsut?

Ei korvaa, vaan toimii niiden päällä. MCP on protokollataso, joka kuljettaa työkalumäärittelyt ja tulokset asiakkaan ja palvelimen välillä. MCP-asiakas muuntaa palvelimen ilmoittamat työkalut alla olevan mallin (OpenAI, Anthropic, Gemini) odottamaan funktiokutsuformaattiin.

Mitkä kielimallit tukevat MCP:tä?

MCP on mallista riippumaton, koska yhteensopivuus on asiakassovelluksessa, ei mallissa. Claude Desktop, Cursor, Zed, Windsurf, Continue.dev ja kymmenet muut tukevat sitä. OpenAI ilmoitti virallisen MCP-tuen Agents SDK:lle kevään 2025 päivityksessä, ja Geminin Code Assist tukee sitä myös.

Voiko MCP-palvelin toimia pilvessä?

Kyllä. Streamable HTTP -kuljetus on suunniteltu juuri tähän. Voit ajaa palvelimen Cloud Runissa, Fly.io:ssa, Vercelissä tai missä tahansa Node.js/Python-ympäristössä. Suojaa päätepiste OAuth 2.1:llä ja Resource Indicators -mekanismilla.

Mistä löydän valmiita MCP-palvelimia?

Virallinen rekisteri löytyy osoitteesta modelcontextprotocol.io/servers, ja yhteisön ylläpitämä lista GitHubin modelcontextprotocol/servers-reposta. Kesäkuussa 2026 julkisia palvelimia oli yli 5 000, kattaen GitHub, GitLab, Slack, Postgres, SQLite, Figma, Notion, Linear ja Sentry.

Tarvitsenko MCP:tä jos rakennan vain yhden agentin?

Et välttämättä. Yhden sovelluksen sisäisille työkaluille suora funktiokutsu on yksinkertaisempi. MCP kannattaa kun työkaluja jaetaan useamman sovelluksen, tiimin tai ulkoisen asiakkaan kesken, tai kun haluat hyödyntää valmista MCP-palvelinekosysteemiä (esim. GitHub-, Postgres- ja Slack-integraatiot).

Editorial Team
Tietoa Kirjoittajasta Editorial Team

Our team of expert writers and editors.