MCP server: Komplett guide til custom integrasjon i 2026

Oppdatert 26. april 2026
MCP server kobler ChatGPT og Claude til dine egne data. Lær hvordan du bygger en custom mcp server med kode, deploy og 2026-eksempel — start gratis.

Kortversjonen

MCP-servere kobler interne datasystemer til AI-modeller som ChatGPT via en åpen protokoll. Med Python og FastMCP kan du bygge en fungerende, read-only integrasjon på 4–8 timer. Viktige tips: slim ned payloads, bruk readOnlyHint, støtt SSE-transport og håndter auth via OAuth.

Oppsummeringen er laget med kunstig intelligens. 

En mcp server er en programmerbar bro som kobler dataene dine til AI-modeller som ChatGPT og Claude — over en åpen protokoll Anthropic publiserte i 2024. Riktig satt opp gir én mcp server hele teamet ditt et søkbart, agentisk grensesnitt mot interne systemer på 4–8 timers utviklingstid. Denne guiden viser hvordan, basert på en ekte case vi bygget for Tverrkirkelig.

Hos Nettsmed bygde vi nylig en mcp server som eksponerer Cornerstone medlemsregister som lesetilgang for ChatGPT Workspace Agents. Denne artikkelen er den teknisk-konkrete oppskriften — Python-kode, Vercel-deploy og hvilke fellgruver vi traff på underveis.

Hva er en mcp server?

Model Context Protocol (MCP) er en åpen standard som lar AI-modeller kalle eksterne verktøy gjennom et JSON-RPC-grensesnitt. En mcp server eksponerer disse verktøyene — typisk lese- eller skriveoperasjoner mot dine egne datasystemer — så ChatGPT, Claude eller andre AI-klienter kan bruke dem.

Tre typer mcp server-transport finnes i dag:

  • stdio — for lokal bruk fra Claude Code, Claude Desktop og lignende. Enklest å starte med.
  • Streamable HTTP — for moderne klienter (Claude Apps SDK, OpenAI Agents SDK).
  • SSE (Server-Sent Events) — kreves av ChatGPT Workspace Agents per april 2026.

For en mcp server som skal serve ChatGPT-agenter må du støtte SSE. Vi anbefaler å eksponere både SSE og streamable HTTP fra samme prosess slik at samme kode dekker alle klienter.

Stack: hva vi brukte og hvorfor

  • Python 3.13 + FastMCP — Anthropics offisielle MCP SDK. Decorator-basert tool-registrering, mindre boilerplate enn å bygge fra bunn.
  • FastAPI / Starlette — for HTTP/SSE-endepunkter (FastMCP gir Starlette-app ut av boksen).
  • httpx — async HTTP-klient mot underliggende API.
  • Vercel — deploy. Auto-detekterer FastAPI, gratis preview-deploys, EU-region tilgjengelig.
  • Pydantic — input-validering på tool-argumenter.

Hele oppsettet for vår mcp server tok rundt 4 timer fra blank repo til fungerende endepunkt — inkludert testing mot live-data. Det er ikke et komplekst prosjekt hvis du har erfaring med Python og REST API-er fra før.

Steg 1: Scaffold prosjektet

Lag et nytt Python-prosjekt med FastMCP som hoveddependens. Strukturen vi bruker:

cornerstone-mcp/
├── api/
│   └── index.py              # Vercel serverless entry
├── src/
│   └── cornerstone_mcp/
│       ├── __init__.py
│       ├── config.py         # env vars
│       ├── client.py         # underlying API client
│       ├── server.py         # FastMCP + tools
│       └── http.py           # HTTP/SSE app
├── pyproject.toml
├── requirements.txt
└── vercel.jsonCode language: PHP (php)

Nøkkeldependenser i requirements.txt:

mcp>=1.2.0
fastapi>=0.110.0
uvicorn[standard]>=0.27.0
httpx>=0.27.0
python-dotenv>=1.0.0
pydantic>=2.6.0

Steg 2: Definer tools med FastMCP

FastMCP bruker Python-decorators for å registrere tools. Hver tool blir et JSON-RPC-method AI-en kan kalle. Slik definerer vi tools i vår mcp server:

from mcp.server.fastmcp import FastMCP
from mcp.types import ToolAnnotations

mcp = FastMCP(
    "cornerstone-mcp",
    instructions="Read-only access to lokallag, members and Frifond data.",
    stateless_http=True,
    json_response=True,
)

RO = ToolAnnotations(
    readOnlyHint=True,
    destructiveHint=False,
    idempotentHint=True,
    openWorldHint=False,
)

@mcp.tool(annotations=RO)
async def search_groups(query: str) -> str:
    """Search lokallag by name. USE THIS WHEN you know a name and need an id."""
    results = await client.search_groups(query)
    return json.dumps(results, ensure_ascii=False)Code language: PHP (php)

Tre detaljer som er lett å overse:

  • readOnlyHint=True — uten denne flagger ChatGPT alle tools som «WRITE / DESTRUCTIVE» i UI-en, og brukerne får advarsler.
  • «USE THIS WHEN»-pattern i docstring — LLM-en plukker rett tool basert på beskrivelsen. Vær eksplisitt på når tool-en skal brukes.
  • stateless_http=True — påkrevd for serverless-deploy (Vercel). Hver request er selvstendig.

Steg 3: Slim payloads for LLM-ergonomi

Den vanligste feilen i en ny mcp server er å returnere for mye data. ChatGPT har begrenset context-window, og en tool-respons på 290 000 tokens drukner svaret. Vår første list_groups returnerte 290 KB — agenten klarte ikke å hente ut konkrete grupper.

Løsningen: returner kun det nødvendige feltsettet, og lag separate tools for tunge spørringer:

  • list_groups — slim records (id, navn, leder), ~11 KB total.
  • search_groups(query) — server-side filter, kun matchende rader.
  • get_group(id) — fulle detaljer for én gruppe, ~2 KB.
  • get_group_members(id, year) — eksplisitt opt-in for tunge medlemslister.

Etter slimmingen klarer ChatGPT å svare på «hvor mange medlemmer har Echo i 2024?» med ett tool-kall i stedet for fem. Hold tools små og fokuserte — det gjelder enhver mcp server.

Steg 4: Eksponer både SSE og streamable HTTP

FastMCP gir deg mcp.streamable_http_app() og mcp.sse_app() som separate Starlette-apper. Begge må aktiveres i samme prosess for å støtte både ChatGPT (SSE) og Claude Apps SDK (streamable HTTP):

from starlette.applications import Starlette
from starlette.routing import Mount, Route
import contextlib

streamable = mcp.streamable_http_app()
sse = mcp.sse_app()

async def dispatch(scope, receive, send):
    path = scope.get("path", "")
    if path.startswith("/sse") or path.startswith("/messages"):
        await sse(scope, receive, send)
    else:
        await streamable(scope, receive, send)

@contextlib.asynccontextmanager
async def lifespan(_app):
    async with mcp.session_manager.run():
        yield

app = Starlette(
    routes=[Route("/healthz", lambda r: JSONResponse({"ok": 1})),
            Mount("/", app=dispatch)],
    lifespan=lifespan,
)Code language: JavaScript (javascript)

Husk lifespan-konteksten — uten den får du RuntimeError: Task group is not initialized ved første tool-kall. FastMCPs streamable-håndterer trenger en aktiv async-kontekst.

Steg 5: Fiks DNS rebinding-protection

FastMCP slår på DNS rebinding-beskyttelse som default. Det betyr at en mcp server avviser requests med Host-header som ikke står i allowlist. Resultat: 421 Misdirected Request i prod hvis du glemmer det.

from mcp.server.transport_security import TransportSecuritySettings

security = TransportSecuritySettings(
    enable_dns_rebinding_protection=True,
    allowed_hosts=[
        "localhost",
        "127.0.0.1",
        "din-mcp.vercel.app",
    ],
)

mcp = FastMCP(..., transport_security=security)Code language: JavaScript (javascript)

Steg 6: Deploy til Vercel

Vercel auto-detekterer FastAPI/Starlette via app-variabelen. Lag api/index.py som re-eksporterer Starlette-appen:

# api/index.py
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

from cornerstone_mcp.http import app  # noqaCode language: PHP (php)

Og en minimal vercel.json:

{
  "rewrites": [
    { "source": "/(.*)", "destination": "/api/index" }
  ]
}Code language: JSON / JSON with Comments (json)

Sett env vars med vercel env add. Bruk printf, ikke echo — sistnevnte legger til newline som bryter HTTP-headere senere. Etter vercel --prod har du en mcp server live.

Steg 7: Auth — den vanskeligste biten

ChatGPT custom MCP-connectorer støtter kun OAuth eller no-auth. Statisk bearer-token i header — som er den intuitive løsningen — fungerer ikke. Tre realistiske valg for en kunde-prod mcp server:

  • OAuth med dynamic client registration — korrekt løsning. ChatGPT henter .well-known/oauth-authorization-server, registrerer seg som klient og henter token. 1–2 dagers utviklingsjobb første gang.
  • OAuth via proxy (Cloudflare Access, Auth0, Stytch) — outsource kompleksiteten.
  • No-auth med URL-obscurity + PII-filter — read-only data, lite gjettbar URL, eksterne kall logges. Akseptabelt for testfase, ikke for langsiktig prod.

For Claude Apps SDK og Apps SDK-baserte klienter er bearer-token i header OK. For ChatGPT må du ned i OAuth-løypa eller bruke proxy.

Steg 8: Test mot ekte AI-klient

Smoke-test først via curl:

curl -sS -X POST https://din-mcp.vercel.app/mcp 
  -H 'Content-Type: application/json' 
  -H 'Accept: application/json, text/event-stream' 
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' 
  | jq '.result.tools[].name'Code language: JavaScript (javascript)

Deretter koble på ChatGPT Workspace Agent, Claude Desktop eller egen agent og kjør 5–10 reelle spørsmål mot din mcp server. Mål: hvor mange tool-kall trengs per svar? Mer enn 3 betyr at tool-design eller server-instructions må strammes.

Vanlige fallgruver med en mcp server

  • For store payloads. Returnerer du 50 KB+ per tool? Slim ned eller del opp i flere tools.
  • Glemt readOnlyHint. Tools markeres som DESTRUCTIVE i ChatGPT uten denne. Brukerne får advarsler.
  • Glemt host allowlist. Vercel-deploy gir 421 hvis Host-header ikke er whitelisted.
  • Cross-invocation cache. In-memory cache forsvinner mellom Vercel-invocations. Bruk Vercel KV hvis du trenger persistens.
  • Statisk bearer for ChatGPT. Fungerer ikke. Du må ha OAuth eller no-auth.

Cornerstone-MCP: vår faktiske case

Vi bygde denne for Tverrkirkelig (Levende Tverrkirkelig Ungdom). Servern eksponerer 14 read-only tools mot Cornerstones GraphQL: lokallag-søk, medlemstall per år, Frifond-utbetalinger, og en formel-basert kalkulator som estimerer LNUs neste tildeling.

  • Repo: github.com/Sinfjell/cornerstone-mcp (åpen kildekode)
  • Live: cornerstone-mcp.vercel.app/mcp
  • Tools: 14 read-only, alle annotert som readOnlyHint=True
  • Total kode: ~600 linjer Python, inkludert tester

Den brukes nå som data-lag for en ChatGPT Workspace Agent som svarer ansatte på spørsmål om medlemstall, Frifond-historikk og søknadsvurdering. Brukstidsbesparelse: 30–90 sekunder per spørsmål, 20–40 spørsmål i uken — typisk for en mcp server med fokusert scope.

Spørsmål om mcp server

Klar for å bygge en mcp server?

Hvis du har et internt datasystem teamet bruker daglig og lurer på om en mcp server vil løse problemet, ta kontakt for en gratis discovery-samtale. Vi kartlegger 3–5 høyverdige use cases, gir et fast tilbud, og leverer på 4–6 uker. Ta kontakt eller les mer om custom AI integrasjon generelt.

Trenger du dypere bakgrunn først? Bygge AI agent dekker build vs buy, og AI agent case Nora viser et komplett norsk eksempel. For den offisielle MCP-spec, se modelcontextprotocol.io.

Flere artikler

Skrevet 26. april 2026
Custom ai integrasjon kobler bedriftens egne systemer til ChatGPT og Claude. Få 7 steg, priser og use cases — book gratis discovery hos Nettsmed....

Skrevet 25. april 2026
AI agent begrensninger i 2026: 5 ting AI-agenter ikke kan gjøre (ennå), og hvordan norske bedrifter unngår å kjøpe inn på hype før teknologien er moden....

Skrevet 25. april 2026
AI agent GDPR i 2026: hva norske bedrifter må sjekke før de eksponerer kunde-data for ChatGPT, Copilot eller en custom-agent. 5 viktige sjekkpunkter....