Skip to main content
Use custom credentials and MCP servers when the built-in integration catalog does not cover the service you need, or when you’re connecting to an internal API. Most custom integrations start simple: define a credential, write an action that uses it, then attach that action to workflows or agents.

Example requests

Ask your coding agent which API or MCP server you want to reach. It can define the credential, write the actions, and attach them.
“Connect to our internal billing API and add actions to look up and refund an invoice.”
“Attach the DeepWiki MCP server to the research agent so it can answer questions about any GitHub repo.”

Define a custom API key credential

Use defineCredential() for static secrets. The key is the credential slug users will set in the web app or CLI, and fields describes the secret shape.
src/credentials/acme.ts
import { defineCredential } from "@keystrokehq/keystroke/credentials";
import { z } from "zod";

export const acme = defineCredential({
  key: "acme",
  fields: {
    apiKey: z.string(),
  },
});
Then declare it on an action:
src/actions/create-acme-ticket.ts
import { defineAction } from "@keystrokehq/keystroke/action";
import { z } from "zod";
import { acme } from "../credentials/acme";

export const createAcmeTicket = defineAction({
  slug: "create-acme-ticket",
  input: z.object({ title: z.string(), body: z.string() }),
  output: z.object({ id: z.string() }),
  credentials: [acme] as const,
  async run(input, credentials) {
    return createTicket({
      apiKey: credentials.acme.apiKey,
      title: input.title,
      body: input.body,
    });
  },
});
Connect the credential:
keystroke credentials set acme --set apiKey=@env:ACME_API_KEY --scope org
See using credentials in code for scope resolution.

Wrap a custom app

If you have several actions for the same service, you can define an app wrapper and create actions from it. This keeps the credential definition shared across all actions.
src/apps/acme.ts
import { defineApp } from "@keystrokehq/keystroke/app";
import { z } from "zod";

export const acme = defineApp({
  slug: "acme",
  auth: "api_key",
  credential: {
    apiKey: z.string(),
  },
});
src/actions/create-acme-ticket.ts
import { z } from "zod";
import { acme } from "../apps/acme";

export const createAcmeTicket = acme.action({
  slug: "create-acme-ticket",
  input: z.object({ title: z.string(), body: z.string() }),
  output: z.object({ id: z.string() }),
  async run(input, credentials) {
    return createTicket({
      apiKey: credentials.acme.apiKey,
      title: input.title,
      body: input.body,
    });
  },
});
This is mainly useful for package-style integrations or when you want a family of actions to share one app credential.

Connect an MCP server

Agents can connect to any MCP server you define in code. MCP tools are attached through the agent’s tools array, just like actions.
src/agents/researcher.ts
import { defineAgent, defineMcp } from "@keystrokehq/keystroke/agent";

const deepwiki = defineMcp({
  key: "deepwiki",
  transport: {
    type: "http",
    url: "https://mcp.deepwiki.com/mcp",
  },
});

export default defineAgent({
  slug: "researcher",
  systemPrompt: "Use DeepWiki tools for questions about GitHub repositories.",
  model: "anthropic/claude-sonnet-4.6",
  tools: [deepwiki],
});
If the MCP server needs authentication, declare credentials on the MCP definition and map them into headers:
const internalMcp = defineMcp({
  key: "internal",
  transport: { type: "http", url: "https://mcp.example.com" },
  credentials: [acme] as const,
  auth: (credentials) => ({
    headers: { Authorization: `Bearer ${credentials.acme.apiKey}` },
  }),
});
You cannot register arbitrary MCP servers from the web app yet. Custom MCP servers are authored in code and deployed with the project.

Current limitations

keystroke.config.ts has an integrations option, but custom HTTP integration mounting is not a shipped user-facing extension point yet. Today, use:
  • defineCredential() plus actions for custom APIs.
  • defineApp() for a reusable app/action wrapper.
  • defineMcp() for custom MCP servers attached to agents.
Hosted MCP management and managed service settings in the web app are not general-availability features today. Treat code-defined MCP servers as the supported custom MCP path.

Next steps

Using credentials in code

Understand credential declaration, scopes, and defaults.

Actions

Build the action that consumes your custom credential.

Build agents

Attach actions and MCP servers as agent tools.

Connect and manage apps

Store the API key or OAuth credential your code will resolve.