Skip to main content
Call kontext.require() inside your tool handlers to get credentials for any connected integration. The SDK handles token exchange, caching, and error handling. There are two supported call shapes:
  • kontext.require("github", authInfo.token) when you have the authenticated user’s Kontext access token.
  • kontext.require("github", { userId }) when your confidential server already knows the caller’s external subject ID and external auth is configured.
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 },
  });

  const repos = await res.json();
  return { content: [{ type: "text", text: JSON.stringify(repos, null, 2) }] };
});

IntegrationCredential shape

kontext.require() returns an IntegrationCredential object:
interface IntegrationCredential {
  accessToken: string;        // Raw access token
  tokenType: string;          // Usually "Bearer"
  authorization: string;      // Pre-formatted header: "Bearer <token>"
  expiresIn?: number;         // Seconds until expiry
  scope?: string;             // Granted scopes
  integration: string;        // Integration name (e.g. "github")
}
The authorization field is ready to drop into an HTTP header:
const github = await kontext.require("github", authInfo!.token);

await fetch("https://api.github.com/user", {
  headers: { Authorization: github.authorization },
});

Built-in caching

The SDK caches credentials per integration per token using an LRU cache (max 500 entries). Cache TTL is the minimum of expiresIn - 60s and 5 minutes. You do not need to cache credentials yourself. Repeated calls to kontext.require("github", token) within the same session return the cached credential without a network round-trip. The SDK keeps token-mode and userId-mode exchanges in separate cache buckets, so the two flows never collide.

Exchange by external user ID

Use { userId } for hard-cutover partner or credential-vault flows where your backend already has a stable external identifier for the end user.
const github = await kontext.require("github", {
  userId: "platform-user-123",
});

await fetch("https://api.github.com/user", {
  headers: { Authorization: github.authorization },
});
This path is intended for confidential server applications. Kontext treats the userId as the RFC 8693 subject_token with the custom type urn:kontext:user-id.

Error handling

When a user has not connected an integration, kontext.require() throws an IntegrationConnectionRequiredError. This error may include a connectUrl that the user can open in a browser to authorize the integration.
import {
  Kontext,
  IntegrationConnectionRequiredError,
} from "@kontext-dev/js-sdk/server";

server.tool("list_repos", "List GitHub repos", {}, async (_args, { authInfo }) => {
  try {
    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()) }] };
  } catch (err) {
    if (err instanceof IntegrationConnectionRequiredError) {
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            error: "integration_required",
            message: err.message,
            integration: err.integrationName ?? err.integrationId,
            connect_url: err.connectUrl,
          }),
        }],
        isError: true,
      };
    }
    throw err;
  }
});
The error has these fields:
FieldTypeDescription
integrationIdstringIntegration identifier
integrationNamestring | undefinedHuman-readable name
connectUrlstring | undefinedURL for the user to authorize the integration
codestringAlways "kontext_integration_connection_required"
When you call kontext.require() with { userId }, connectUrl is intentionally omitted. That mode has no bearer token available to mint a user-facing connect session, so your app must route the user through its own connect flow. MCP clients that support elicitation will display the connectUrl to the user automatically when it is present. Return it in the tool response so the AI model can instruct the user.

requireCredentials() for credential-based integrations

Some integrations use API keys or other static credentials instead of OAuth tokens. Use requireCredentials() to resolve these.
const creds = await kontext.requireCredentials("my-internal-api", authInfo!.token);

// creds.credentials is a Record<string, string>
await fetch("https://internal.example.com/api", {
  headers: { "X-API-Key": creds.credentials.api_key },
});
requireCredentials() returns:
interface IntegrationResolvedCredentials {
  integration: string;                  // Original integration name
  integrationId: string;                // Canonical UUID
  credentials: Record<string, string>;  // Key-value credential map
}
This method also throws IntegrationConnectionRequiredError if the user has not provided the required credentials.

Known integrations

The SDK provides type hints for common integrations:
  • github, slack, linear, notion, jira, confluence
  • gmail, google-calendar, google-drive, figma
  • stripe, shopify, salesforce, hubspot, asana
  • discord, twilio, sendgrid, openai, anthropic
You can also pass any custom string for integrations you define in the Kontext dashboard.

Next steps

  • Production — Deployment checklist for running in production.
  • Server Types — Full type reference for IntegrationCredential and IntegrationResolvedCredentials.
  • Errors — Full error hierarchy, error codes, and handling patterns.