MCP-protokoll: teknisk guide för utvecklare 2026
Hur du bygger en säker MCP-server från grunden: arkitektur, autentisering, testning och produktionsdrift. Steg för steg med TypeScript SDK och kodexempel.

MCP-protokoll har gått från Anthropic-experiment till industri-standard på 18 månader. För utvecklare och CTOs som vill bygga AI-agenter mot egna system är frågan inte längre om MCP, utan hur du implementerar det säkert i produktion. Den här guiden är teknisk: arkitektur, kod, autentisering och övervakning.
Om du är ny till protokollet, läs först vår grundläggande genomgång av MCP. Den här guiden förutsätter att du vet vad MCP är och vill bygga något själv.
Hur fungerar MCP-arkitekturen tekniskt?
MCP-protokoll bygger på JSON-RPC 2.0 över två transport-typer: stdio (lokala servrar) och HTTP med Server-Sent Events (remote servrar). Klienten initierar en handshake där server och klient utbyter capabilities, sedan flödar bidirektionell kommunikation med strukturerade meddelanden.
De tre lagren i arkitekturen
Arkitekturen har tre lager. Det översta lagret är klienten (Claude Desktop, Cursor, eller en egen app som använder Anthropic SDK). Det mellersta lagret är transportprotokollet som bär meddelanden, antingen via standard input/output för lokala processer eller HTTP+SSE för nätverkstjänster. Det understa lagret är själva MCP-servern som exponerar Resources, Tools och Prompts.
Handshake-flödet är standardiserat. Klienten skickar initialize med sin protocol-version och vilka capabilities den stödjer. Servern svarar med samma fält + server-info. Båda sidor förhandlar vad de kan göra. Detta är dokumenterat i den officiella protokoll-specifikationen.
Tre skillnader mot REST
Vad gör MCP-protokoll annorlunda från en vanlig REST-API? Tre saker som spelar roll i implementation:
Stateful sessions. En MCP-anslutning har långlivad state. Klient och server kommer ihåg vad de förhandlat fram. REST är stateless per request – MCP är mer som WebSocket.
Capability negotiation. Servern berättar för klienten exakt vilka Resources, Tools och Prompts den stödjer vid uppstart. Inga gissningar, ingen swagger-fil att underhålla separat.
Notifications-stöd. Servern kan pusha uppdateringar till klienten (t.ex. "resurs X har ändrats"). REST kräver polling eller separata webhook-system.
Gemensam nämnare för de tre är JSON-RPC, ett transportagnostiskt RPC-format definierat i den officiella JSON-RPC 2.0-specifikationen. Eftersom protokollet är oberoende av transporten kan MCP köra identiska meddelanden över både stdio och HTTP utan att du skriver om logiken.
Hur bygger du en MCP-server från grunden?
Det enklaste sättet att bygga en MCP-server är TypeScript SDK från Anthropic. Du installerar paketet, definierar dina tools eller resources, och kör servern via stdio för lokala anrop eller HTTP för remote. En minimal server är cirka 30 rader kod.
Installation:
npm install @modelcontextprotocol/sdk
Här är en minimal MCP-server som exponerar ett enda tool för att hämta dagens datum:
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: 'datum-server',
version: '1.0.0',
})
server.tool(
'get_current_date',
'Hämtar dagens datum i ISO 8601-format',
{
timezone: z.string().optional().describe('IANA-timezone, t.ex. Europe/Stockholm'),
},
async ({ timezone = 'Europe/Stockholm' }) => {
const date = new Date().toLocaleString('sv-SE', { timeZone: timezone })
return {
content: [{ type: 'text', text: date }],
}
}
)
const transport = new StdioServerTransport()
await server.connect(transport)
Koden gör tre saker. Skapar en server-instans med namn och version, registrerar ett tool med Zod-schema för input-validation, och kopplar servern till stdio-transporten. När Claude Desktop startar servern kommer användaren se get_current_date som ett tillgängligt verktyg.
För att exponera Resources (data som klienten kan läsa) istället för Tools (funktioner som körs), använder du server.resource(). Skillnaden är semantisk: Resources är read-only data, Tools är actions som kan ha sideeffects. Den officiella TypeScript SDK-dokumentationen har exempel för båda mönstren.
Python-utvecklare använder Python SDK med samma decorator-baserade pattern. Båda SDK:erna har bred uppslutning: TypeScript SDK:n ligger på cirka 12 700 GitHub-stjärnor och Python SDK:n på cirka 23 000 (stjärnsiffran syns på respektive repo-sida), och båda uppdateras regelbundet av Anthropic.
För production deployment byter du transport från stdio till HTTP+SSE. Det kräver ett par extra rader för att starta en Express-server eller liknande HTTP-runtime. Då blir servern nåbar över nätverket istället för bara lokalt.
Hur säkrar du auth och permissions i MCP?
MCP-protokoll har inget inbyggt auth-lager. Säkerheten implementerar du i transportlagret eller per verktyg. Tre vanliga mönster: API-key-baserad auth för enkla scenarier, OAuth 2.1 för enterprise och tredjepartsintegrationer, och mTLS för säker server-till-server-kommunikation inom samma interna infrastruktur.
För lokala stdio-servrar är auth oftast inte ett problem eftersom användaren kör processen själv med sin egen behörighet. För HTTP-baserade remote-servrar blir auth kritiskt. Här är mönstret för API-nyckel i Bearer-token, som är det enklaste säkra alternativet:
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('/mcp', (req, res, next) => {
const auth = req.headers.authorization
const expected = `Bearer ${process.env.MCP_API_KEY}`
if (!process.env.MCP_API_KEY) {
return res.status(503).json({ error: 'MCP_API_KEY not configured' })
}
if (auth !== expected) {
return res.status(401).json({ error: 'Unauthorized' })
}
next()
})
const server = new McpServer({ name: 'protected-server', version: '1.0.0' })
// ...registrera tools här...
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => crypto.randomUUID() })
await server.connect(transport)
app.use('/mcp', transport.handler)
app.listen(3000)
Scoping är nästa lager. Inte alla klienter ska kunna anropa alla tools. Per-tool authorization kan implementeras genom att verifiera klientens identitet (via JWT-claims eller liknande) inne i tool-handlern och returnera permission-error om scope saknas.
Scoping, OAuth och sandbox-isolering
För OAuth 2.1-baserad auth följer du standard-flow med en separat OAuth-server som issues access-tokens. OAuth 2.1 är i sig ett pågående IETF-arbete som konsoliderar OAuth 2.0 och senare RFC:er till ett enklare kärndokument, definierat i IETF-utkastet för OAuth 2.1. MCP-protokoll har en officiell auth-specifikation som beskriver hur tokens passas i Bearer-headers. Anthropic rekommenderar OAuth för publik exponering av MCP-servrar.
Sandbox-isolering är viktig för enterprise. Om din MCP-server kör mot en produktionsdatabas, sätt strikta SQL-permissions på den användaren som servern kör som. Aldrig SUPERUSER. Aldrig DROP TABLE. Standardprincipen är minsta möjliga privilegium per tool.
Hur testar och debuggar du MCP-servrar?
Det officiella verktyget är MCP Inspector: en webbaserad UI som låter dig anropa tools, inspektera responses, och se hela JSON-RPC-trafiken i realtid. Du installerar det med npm och pekar det mot din lokala eller remote server.
Installation och uppstart:
npx @modelcontextprotocol/inspector node ./dist/server.js
Detta startar Inspector på localhost:5173 och spawnar din server som child-process via stdio. UI:n visar en lista över alla registrerade tools, resources och prompts. Du kan anropa varje tool med custom-input och se exakt vad servern svarar.
För HTTP-baserade servrar anger du URL och eventuell auth-header. Inspector hanterar SSE-streaming och visar request/response-paren i en tidslinje. Detta är ovärderligt för att felsöka capability-negotiation och tool-call-fel.
Loggning på serversidan är lika viktigt som Inspector. Eftersom MCP-protokoll använder stdio för lokala servrar är vanliga console.log-anrop farliga. De korrumperar JSON-RPC-strömmen och bryter klientanslutningen omedelbart. Använd console.error (stderr) för all loggning eller en strukturerad logger som pino. För HTTP-servrar gäller vanlig request-loggning utan stdio-risken.
Tre vanliga buggar i praktiken
Tre vanliga buggar vi sett i konsultarbete för svenska mindre företag. De tre kommer i den ordning de brukar dyka upp, och timeout-buggen är den som stjäl mest felsökningstid eftersom symtomet (servern verkar svara, men klienten ger inget resultat) pekar åt fel håll.
Tool-schemas matchar inte verkligheten. Den vanligaste och syns oftast redan första testdagen. En Tool deklarerar att email är required, men handlern crashar på email: null. Lösning: använd Zod (eller liknande) för strict input-validation, inte bara TypeScript-typing.
Long-running tools timeout:ar. Den som kostar mest tid att felsöka, just för att den ser ut som något annat. MCP-klientens default-request-timeout är 60 sekunder: den konstant (DEFAULT_REQUEST_TIMEOUT_MSEC = 60000) ligger hårdkodad i SDK:n, vilket SDK:ns API-dokumentation bekräftar. Gör din tool ett tungt API-call eller väntar på en extern process, hinner servern svara men klienten har redan slutat lyssna. Lösning: implementera progress-notifications via MCP:s notification-mekanism (de nollställer timeouten) eller bryt upp arbetet i mindre anrop.
Resource-URI:er kolliderar. Sällsynt, men lömsk eftersom inget kraschar – fel data returneras tyst. Om två resources har samma URI överskrivs den ena. Lösning: använd hierarkisk URI-design (db://customers/123 istället för customer-123).
För djupare felsökning, läs Inspector-dokumentationen på GitHub.
Vad krävs för att köra MCP i produktion?
Tre saker är kritiska i produktion: rate-limiting så en buggig klient inte hämtar 10 000 poster per minut, felhantering så fel inte läcker stack-traces till klienten, och observerbarhet så att du kan reagera på incidenter i tid.
Rate-limiting implementerar du i transportlagret. För HTTP-baserade servrar fungerar standardbibliotek som express-rate-limit direkt. Sätt initialt 60–100 anrop per minut per API-nyckel och justera baserat på faktisk användning. För stdio-servrar är rate-limiting mindre kritiskt eftersom klienten kör lokalt och styrs av användaren.
Error-handling i MCP-protokoll följer JSON-RPC-konventionen. Returnera ett strukturerat error-objekt med code, message, och valfritt data:
server.tool('fetch_customer', 'Hämta kunddata', { id: z.string() }, async ({ id }) => {
try {
const customer = await db.query('SELECT * FROM customers WHERE id = $1', [id])
if (!customer) {
return {
content: [{ type: 'text', text: `Kund med id ${id} hittades inte` }],
isError: true,
}
}
return { content: [{ type: 'text', text: JSON.stringify(customer) }] }
} catch (err) {
// Logga full error på server-sidan, returnera sanitized message
console.error('fetch_customer error:', err)
return {
content: [{ type: 'text', text: 'Internt fel vid kundhämtning' }],
isError: true,
}
}
})
Aldrig returnera raw exception-messages till klienten. De kan innehålla credentials, file-paths eller annan känslig info som AI-modellen sedan repeterar i sitt svar till slutanvändaren.
Secrets, versionering och observerbarhet
Secrets-hantering hör till samma kategori. API-nycklar och databas-credentials ska in via miljövariabler eller en secrets-manager (Vault, AWS Secrets Manager, Doppler), aldrig hårdkodade i server-koden eller i klientens config-fil. Kom ihåg att klientens MCP-config ofta ligger i klartext på användarens maskin: allt som står där ska betraktas som synligt för användaren.
Versionering är nästa fråga. MCP-protokoll har protocol-version i handshaken (2025-11-25 är aktuell daterad specifikation). Din servers egen version sätter du i McpServer-konstruktorn. Semantic versioning rekommenderas: breaking changes i tool-signaturer = major bump.
Observability: logga varje tool-call med tool-name, klient-identifier, duration och success/failure. Detta gör att du kan se vilka tools som faktiskt används, vilka som är långsamma, och vilka som returnerar fel. Standard-loggers som Pino eller Winston fungerar utmärkt. För enterprise: skicka logs till Datadog, Honeycomb eller motsvarande.
Konkret monitoring-pattern som fungerar i produktion:
import { performance } from 'perf_hooks'
server.tool('fetch_data', 'Hämtar data', { id: z.string() }, async ({ id }) => {
const start = performance.now()
const clientId = process.env.MCP_CLIENT_ID ?? 'unknown'
try {
const result = await fetchFromSource(id)
const duration = performance.now() - start
logger.info({ tool: 'fetch_data', clientId, duration, status: 'success' })
return { content: [{ type: 'text', text: JSON.stringify(result) }] }
} catch (err) {
const duration = performance.now() - start
logger.error({ tool: 'fetch_data', clientId, duration, status: 'error', err })
return { content: [{ type: 'text', text: 'Internt fel' }], isError: true }
}
})
De fyra fält som spelar roll i monitoring: tool (vilket verktyg), clientId (vem anropade), duration (latency-mätning), och status (success/error). Med dessa kan du bygga dashboards som visar tool-usage per klient, p95-latencies per tool, och error-rates över tid. Detta är minimum för att kunna debugga incidenter och prioritera optimeringar i produktionen.
Hur integrerar du MCP mot enterprise-system?
Tre stora kategorier av enterprise-integrationer dominerar i konsultarbete: relationsdatabaser (Postgres, SQL Server), interna REST-API:er med befintlig SSO, och SaaS-system som Salesforce eller HubSpot. Varje typ har sitt eget mönster för autentisering, skrivskydd och loggning, och alla tre går att produktionssätta med wrapper-servrar.
För Postgres-integration finns en officiell MCP-server i github.com/modelcontextprotocol/servers. Den exponerar tabeller som Resources och låter klienten köra read-only queries via Tools. För svenska företag är detta ofta tillräckligt: säljaren frågar Claude på naturlig svenska, Claude översätter till SQL, servern kör mot read-replica.
För custom enterprise-API:er rekommenderar vi ett wrapper-mönster: skriv en MCP-server som internt anropar ert REST-API med ett tjänstekonto. Klienten ser MCP-tools, men under huven sker autentisering via OAuth eller mTLS mot er befintliga backend. Detta isolerar AI-modellen från interna implementationsdetaljer och låter er logga + auditera all AI-driven trafik centralt.
För SaaS-integrationer kollar du först om det finns en officiell MCP-server. MCP-registret listar tusentals publika servrar, inklusive officiella från Anthropic för Slack, GitHub och Google Drive. Är ditt SaaS inte täckt? Bygg en wrapper-server mot deras REST-API. Räkna med 1–2 dagar per integration för produktionskvalitet.
Tre saker att tänka på vid enterprise-integration:
Audit-logging är inte valfritt. Varje tool-call ska loggas med klient-identitet, payload och resultat till en separat audit-trail. Detta är ofta krav från compliance/säkerhetsteamet. För svenska företag som omfattas av GDPR är detta särskilt viktigt. För djupare genomgång av regelverkskraven, läs vår guide om EU AI Act för svenska företag.
Sandbox-databas för demo. Innan en MCP-server går mot produktion, testa mot en sandbox-kopia. AI-genererade SQL-queries kan vara kreativa på sätt som överraskar.
Begränsa scope per role. En MCP-server som exponerar hela CRM ger AI-modellen tillgång till hela CRM. Vill du begränsa till "bara denna users konton"? Implementera scoping i tool-handler baserat på klient-identitet.
Vad kostar enterprise-grad MCP-implementation?
Realistisk kostnad för ett mindre företag ligger på 32–56 utvecklartimmar för första MCP-servern, plus hosting och drift på 200–2 000 SEK per månad beroende på trafik. Den första servern är dyrast eftersom infrastrukturen byggs då, medan server två och tre tar 8–15 timmar var.
Anledningen är konkret: auth-skelettet, den strukturerade loggningen och deploy-pipelinen byggs en gång och återanvänds rakt av. Det som återstår på server två är de nya tools-specifika anropen och deras input-validering, inte grundplattan. När vi i konsultarbete sätter upp en andra server mot samma kunds infrastruktur är det i praktiken bara affärslogiken som är ny.
Kostnadsfördelningen för en typisk enterprise-MCP-server:
| Komponent | Timmar | Förklaring |
|---|---|---|
| Server-skelett + tools | 8–12 | Grunduppsättning, första 3–5 tools |
| Auth + scoping | 6–10 | OAuth eller API-nyckel + behörigheter per tool |
| Felhantering + loggning | 4–8 | Strukturerad loggning, audit-trail |
| Testning + Inspector-verifiering | 6–10 | Enhetstester + end-to-end via Inspector |
| Produktionssättning | 4–8 | Containerisering, secrets-hantering, övervakning |
| Dokumentation + överlämning | 4–8 | README, runbooks, utbildning för intern personal |
| Totalt | 32–56 | Första servern, ett system |
För att översätta timmarna till kronor behöver du ett timpris. Svenska konsulttimmar kostar enligt verklig avtalsdata kring 824–852 kr per timme för utvecklarroller på Brainvilles marknadsplats, och Keymans prisbarometer över förseglade avtal visar snitt från 845 kr upp till 1 535 kr per timme för seniora roller. Multiplicerar du tabellens 32–56 timmar mot det spannet landar en första server någonstans mellan cirka 27 000 och 86 000 kr i ren utvecklingstid, beroende på senioritet. Det är inte en offert, men det ger dig en marknadsförankrad ribba att jämföra mot.
Tilläggskostnader varierar. Hosting: en MCP-server på Vercel/Railway/Fly.io kostar 100–500 SEK per månad för rimlig trafik. Övervakning: Datadog eller motsvarande adderar 500–2 000 SEK per månad. Säkerhetsgranskning: en intern granskning lägger 8–16 timmar till första leveransen, lägre för efterföljande.
För en kostnadsöverblick av AI-agent-projekt i bredare bemärkelse, läs vår kostnadsguide för AI-agenter i Sverige. MCP-server är ofta en delkostnad i ett större AI-agent-projekt.
När det gäller skillnaden mellan att bygga en MCP-server och att använda en färdig chatbot-lösning, läs vår jämförelse av AI-agent vs chatbot. MCP-protokoll är vad som skiljer en riktig autonomous agent från en wrapped LLM-call. För en bredare introduktion till hur de här delarna hänger ihop för svenska företag, se vår pillar-artikel om AI-agenter för svenska företag.
Är MCP-protokoll värt investeringen? För Claude-baserade arbetsflöden är svaret tydligt ja. För OpenAI-tunga organisationer är svaret "vänta tills OpenAI släpper officiellt stöd, eller bygg en proxy-server om ni inte kan vänta". Tidsspannet är konkret: Anthropic lanserade MCP den 25 november 2024, så när den här guiden skrivs har protokollet bakom sig runt arton månaders adoption, och kurvan pekar uppåt.
Att signalen inte bara är Anthropics egen syns i oberoende mätningar. I Stackloks branschstudie State of Model Context Protocol in Software 2026, som i december 2025 frågade 300 seniora tekniska beslutsfattare i stora företag, uppgav 45 procent av mjukvarurespondenterna att de redan har MCP-servrar i begränsad eller bred produktion. För ett protokoll som är drygt ett år gammalt är det en ovanligt brant produktionskurva, och det är ett oberoende underlag att väga in vid sidan av leverantörens egna siffror.
Vanliga frågor
Stdio för lokala dev-verktyg (Claude Desktop, Cursor) där servern kör på samma maskin som klienten. HTTP+SSE för remote servrar som flera klienter ska kunna nå över nätverk. Stdio är enklare att sätta upp men begränsad till lokal användning. HTTP kräver mer infrastruktur men ger production-ready deployment med standard auth och rate-limiting.
Ja. Det finns community-SDK:er för Go, Rust, Java och C#. Protokollet är språk-agnostiskt eftersom det bygger på JSON-RPC 2.0 över stdio eller HTTP. Officiella SDK:er från Anthropic finns för TypeScript och Python och får mest underhåll. För andra språk, kolla awesome-mcp-servers-listan för aktuella alternativ.
Semantic versioning per server. Bumpa major-version när du ändrar tool-signaturer eller tar bort resources. Klienter kan se serverns version i handshake. För enterprise-deployments rekommenderas att köra gamla versionen parallellt under 30-90 dagar tills alla klienter migrerat. Detta är samma mönster som API-versionering generellt.
Ja, via progress-notifications. Servern skickar progress-meddelanden under operationens gång till klienten. Notifications är en del av hur MCP-protokoll bygger på JSON-RPC, och de stöds av båda officiella SDK:er. Det är dock inte streaming i HTTP-bemärkelsen, utan diskreta progress-updates med procentvärden eller statusmeddelanden som dessutom nollställer klientens timeout.
Använd MCP SDK:s in-memory transport för unit-tester istället för stdio eller HTTP. Det låter dig anropa tools programmatiskt i Jest eller Vitest utan att spawna en separat process. För end-to-end-tester kan du köra Inspector i headless mode eller skriva en simpel klient med SDK:n som anropar din server och verifierar responses.
Klienten får ett connection-error och behandlar det som tool-failure. Bra praxis är att implementera health-checks och auto-restart i din runtime (Docker, PM2, systemd). För kritiska tools, designa idempotenta operations så att retry är säkert. Loggning av crashed sessions hjälper att hitta root cause.
AI i arbete?



