mcp server
kpn-mcp
MCP server for KPN (Dutch telco): outage + speed checks, SIM swap, business-mobile management
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- Docker Desktop
{
"mcpServers": {
"kpn-mcp": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"KPN_GREXX_USERNAME",
"-e",
"KPN_GREXX_PASSWORD",
"-e",
"KPN_GREXX_BASE_URL",
"-e",
"KPN_GREXX_TOKEN_URL",
"-e",
"KPN_LEGACY_DEVELOPER_API",
"-e",
"KPN_CLIENT_ID",
"-e",
"KPN_CLIENT_SECRET",
"-e",
"KPN_MSM_CLIENT_ID",
"-e",
"KPN_MSM_CLIENT_SECRET",
"-e",
"KPN_BASE_URL",
"-e",
"MCP_TRANSPORT",
"-e",
"AUTH_MODE",
"-e",
"LOG_LEVEL",
"ghcr.io/wyre-ai/kpn-mcp:v2.2.1"
],
"env": {
"KPN_GREXX_USERNAME": "<your KPN_GREXX_USERNAME>",
"KPN_GREXX_PASSWORD": "<your KPN_GREXX_PASSWORD>",
"KPN_GREXX_BASE_URL": "<your KPN_GREXX_BASE_URL>"
}
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 14, 2026kpn-mcp
MCP server for KPN IRMA APIs hosted by Grexx (acceptatie: service-accept.grexx.today), aimed at MSP helpdesks. The default surface is realtime XML over OAuth 2.0 client credentials. The SDK sends HTTP Basic to the token endpoint. POST /realtime uses the Bearer token.
Built on the MCP 2026-07-28 spec via the split v2 SDK
(@modelcontextprotocol/server / /node / /client ^2.0.0-beta.5) with dual-era
serving: one shared McpServerFactory behind createMcpHandler({ legacy: 'stateless' })
answers both 2025-era initialize-handshake clients and modern 2026-07-28 envelope clients,
with the same tool list for every caller. Ships as a GHCR container only (no MCPB bundle).
The client is @wyre-ai/node-kpn (Grexx export).
Contract: docs/GREXX.md.
Tools (15, flat)
-
kpn_grexx_test_connection: the SDK mints an OAuth client-credentials token and posts aZipCodeCheckRequest_V6probe for the public reference address 1012JS 1 (portfolio All). Success means the token endpoint andPOST /realtimeaccepted the Bearer token. -
kpn_grexx_zipcode_check: technology and speeds at a Dutch address (ZipCodeCheckRequest_V6→ZipCodeCheckResponse_V5). -
kpn_grexx_prequalification: address and product-type availability per supplier (PrequalificationRequest_V2→PrequalificationResponse_V1). WhenhasBroadbandis true,serviceIdorreferencePhoneNumberis required. -
kpn_grexx_order_data: customer id, product code, and quantity for an order id (OrderDataRequest_V1→OrderDataResponse_V1). -
11 more realtime tools built from the portal request XSDs (see
docs/GREXX.md):kpn_grexx_carrier_info,kpn_grexx_radius_check,kpn_grexx_ras_check,kpn_grexx_start_line_diagnose,kpn_grexx_customer_data,kpn_grexx_order_summary,kpn_grexx_get_sim,kpn_grexx_mobile_settings,kpn_grexx_mobile_usage,kpn_grexx_mobile_orders,kpn_grexx_available_portings.start_line_diagnosestarts a test at KPN, so it is not read-only and is never retried. SIM codes and the RadiusCheck PPP password are masked.
IRMA enforces XSD element order and rejects a bad request with an HTTP 200
NinaResponse; both are handled by the server. Queued writes and Proxymodule
notifications are not exposed.
Set KPN_LEGACY_DEVELOPER_API=1 to also serve the previous 23 developer.kpn.com tools
(disturbances, availability, SIM swap, MSM). They are absent from the default list.
See docs/DESIGN.md for that catalog. Gated MSM writes still require confirmation.
Credentials
Grexx username and password are the OAuth client_id and client_secret (scope=all).
Copy the interface root from the partner portal (API Gegevens). There is no default
base URL: acceptatie and production differ.
| Env var (env mode) | Gateway header (AUTH_MODE=gateway) | Required |
|---|---|---|
KPN_GREXX_USERNAME | X-KPN-Grexx-Username | yes |
KPN_GREXX_PASSWORD | X-KPN-Grexx-Password | yes |
KPN_GREXX_BASE_URL | none | yes. Interface root, without /realtime |
KPN_GREXX_TOKEN_URL | none | no. Default https://service-accept.grexx.today/oauth/access_token |
Example (acceptatie shape — replace the interface id from API Gegevens):
export KPN_GREXX_USERNAME="..."
export KPN_GREXX_PASSWORD="..."
export KPN_GREXX_BASE_URL="https://service-accept.grexx.today/interfaces/kpn/kpn_partners_acceptatieomgeving/<interface-id>/"
# export KPN_GREXX_TOKEN_URL="https://service-accept.grexx.today/oauth/access_token"
See env.example. Token mint, cache, and Bearer retry live in
@wyre-ai/node-kpn. A header-supplied base URL or token URL is rejected (HTTP 400):
it would send the client secret or Bearer token to a caller-chosen host.
In gateway mode a request missing X-KPN-Grexx-Username or X-KPN-Grexx-Password is
answered 401 (JSON-RPC error -32001) before the MCP handler runs. It never falls
through to env credentials. The gateway does not send the base URL.
When CONDUIT_S2S_SECRET is set, every request except /health and /healthz must also carry a valid
X-Gateway-S2S HMAC header, or it is answered 401. Unset, the check is off.
SDK dependency
Import the Grexx client from @wyre-ai/node-kpn (package root), not /legacy.
The dependency is the published range ^2.1.0 (Prequalification and OrderData from
node-kpn#5, tag v2.1.0). Token minting
is the HTTP Basic behavior from
node-kpn#4. /legacy
remains the developer.kpn.com client for KPN_LEGACY_DEVELOPER_API=1 only.
This server does not mint the Grexx token.
Running
export NODE_AUTH_TOKEN=$(gh auth token) # GitHub Packages auth for @wyre-ai/*
npm install
npm run build
node dist/index.js # stdio (default)
MCP_TRANSPORT=http node dist/index.js # HTTP on :8080 (/mcp, /health)
npm run smoke # both protocol eras serve the same Grexx tools
Docker (linux/amd64 per fleet law):
docker build --platform linux/amd64 --build-arg GITHUB_TOKEN=$(gh auth token) -t kpn-mcp .
docker run -p 8080:8080 \
-e KPN_GREXX_USERNAME=... \
-e KPN_GREXX_PASSWORD=... \
-e KPN_GREXX_BASE_URL=... \
kpn-mcp
/health is a shallow liveness probe. It does not call Grexx.
Legacy developer.kpn.com tools
With KPN_LEGACY_DEVELOPER_API=1 the process also registers kpn_test_connection,
kpn_disturbances_check, kpn_availability_check, kpn_sim_swap_get_date, and the MSM
read/write tools. Credentials are KPN_CLIENT_ID / KPN_CLIENT_SECRET (gateway:
X-KPN-Client-Id / X-KPN-Client-Secret), plus an optional MSM pair. KPN_BASE_URL
stays env-only. A half MSM pair is rejected. MSM writes still create orders, are not
retried, and require confirmation (confirm_destructive_action when the client cannot
be prompted).
Vendor quirks encoded here
- OAuth client_credentials,
scope=all. The SDK sends HTTP Basic to the token endpoint, then Bearer onPOST /realtime(Content-Type: text/xml). Plain XML, no SOAP envelope. Basic Auth is not sent onPOST /realtime. - This server hands token minting to
GrexxClient, which sends HTTP Basic first and may fall back to form-bodyclient_id/client_secretafter HTTP 400/401invalid_client. - The token endpoint is not retried into a Bearer-less call. HTTP 401 remints once inside the SDK.
- IRMA code
108and HTTP 429 are rate limits. Code102is an IP allowlist rejection. - Success codes include
Success(what acceptatie returned for ZipCodeCheck).
License
Apache-2.0 © WYRE Technology