Skip to main content
Kontext is the identity control plane for AI agents. The server SDK is the runtime bridge: your MCP server requests credentials per tool call, while Kontext handles policy enforcement, token brokering, and audit logging centrally. The SDK also handles OAuth metadata, bearer token verification, CORS, session management, and MCP transport, so you can focus on tools and business logic.

Install

npm install @kontext-dev/js-sdk @modelcontextprotocol/sdk express

Minimal example

import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { Kontext } from "@kontext-dev/js-sdk/server";

const kontext = new Kontext({ clientId: "mcp_your-server" });

function createServer() {
  const server = new McpServer({ name: "my-server", version: "1.0.0" });
  server.tool("hello", "Say hello", {}, async () => ({
    content: [{ type: "text", text: "Hello from Kontext" }],
  }));
  return server;
}

const app = express();
app.use(kontext.middleware(() => createServer()));
app.listen(3000);
This gives you a working MCP application with OAuth discovery, authenticated transport, and session management out of the box.

What the middleware handles

When you call kontext.middleware(), it mounts an Express router that handles:
  • OAuth metadataGET /.well-known/oauth-authorization-server responds with authorization server metadata, and GET /.well-known/oauth-protected-resource{mcpPath} (default /.well-known/oauth-protected-resource/mcp) responds with protected resource metadata (RFC 9728). MCP clients use both for discovery.
  • MCP transportPOST /mcp handles the Streamable HTTP MCP transport. Configurable via the mcpPath option.
  • Bearer auth — Every request is verified against the authorization server’s JWKS. Pass a custom verifier to override.
  • CORS — Pre-configured for browser-based MCP clients like the MCP Inspector.
  • Session management — Each session gets tracked, with auto-cleanup after 1 hour of inactivity.

Getting integration credentials

Inside your tool handlers, call kontext.require() with an integration name and either the current user’s Kontext token or a known external end-user ID:
server.tool("list_repos", "List GitHub repos", {}, async (_args, { authInfo }) => {
  const github = await kontext.require("github", authInfo!.token);
  const res = await fetch("https://api.github.com/user/repos", {
    headers: { Authorization: github.authorization },
  });
  return { content: [{ type: "text", text: JSON.stringify(await res.json()) }] };
});
If your confidential server already has an external subject identifier for the end user, you can exchange by ID instead:
const github = await kontext.require("github", {
  userId: "partner-user-123",
});
The SDK exchanges either input using RFC 8693 token exchange, with built-in caching and separate cache keys for token mode vs userId mode.

Next steps

  • Middleware — Configure the Express middleware, session hooks, and custom verifiers.
  • Credentials — Deep dive on require(), error handling, and the elicitation flow.
  • Production — Deployment checklist for running in production.
  • Server Types — Full type reference for Kontext, MiddlewareOptions, and IntegrationCredential.