Connector SDK

Connectors are how agents perceive data and reach external tools. They are MCP-native — every connector is a Model Context Protocol server — and the SDK gives you end-to-end type safety from schema to handler.

#Installation

The Connector SDK is part of @kraken-ai/platform — the same package that ships the Agent SDK and the kraken CLI. Every scaffolded project already depends on it, so there is nothing extra to install.

ts
import { defineConnector, defineTool } from "@kraken-ai/platform";
import * as z from "zod";

A connector is a single file under src/connectors/. Its identity comes from the filename — src/connectors/filesystem.ts is the filesystem connector — never from a field you pass in. The file’s default export is the connector blueprint. See Connectors for the conceptual model.

#defineConnector

defineConnector declares a connector that exposes tools — and optionally resources and prompts — to agents. The example below is the filesystem connector generated by the starter template.

ts
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
import { normalize, resolve } from "node:path";
import { defineConnector, defineTool } from "@kraken-ai/platform";
import * as z from "zod";

const DATA_DIR = resolve(process.env.KRAKEN_DATA_DIR ?? "./data");
await mkdir(DATA_DIR, { recursive: true });

const safePath = (relativePath: string): string => {
  const resolved = resolve(DATA_DIR, normalize(relativePath));
  if (resolved !== DATA_DIR && !resolved.startsWith(`${DATA_DIR}/`)) {
    throw new Error("Path traversal denied");
  }
  return resolved;
};

// File at src/connectors/filesystem.ts → identity = "filesystem"
export default defineConnector({
  displayName: "Filesystem",
  description: "Read and write files in the data directory",
  requiredEnvVars: ["KRAKEN_DATA_DIR"],

  tools: {
    fs_read: defineTool({
      description: "Read a file from the data directory",
      input: z.object({ path: z.string().describe("Relative path within data directory") }),
      handler: async ({ path }: { path: string }) => readFile(safePath(path), "utf-8"),
    }),
    fs_write: defineTool({
      description: "Write content to a file",
      input: z.object({
        path: z.string().describe("Relative path within data directory"),
        content: z.string().describe("File content to write"),
      }),
      annotations: { destructiveHint: true },
      handler: async ({ path, content }: { path: string; content: string }) => {
        const safe = safePath(path);
        await mkdir(resolve(safe, ".."), { recursive: true });
        await writeFile(safe, content, "utf-8");
        return { success: true };
      },
    }),
    fs_list: defineTool({
      description: "List files and directories",
      input: z.object({
        path: z.string().optional().describe("Relative path (defaults to root)"),
      }),
      annotations: { readOnlyHint: true },
      handler: async ({ path }: { path?: string }) => {
        const entries = await readdir(safePath(path ?? "."), { withFileTypes: true });
        return entries.map((e: { name: string; isDirectory: () => boolean }) => ({
          name: e.name,
          type: e.isDirectory() ? "dir" : "file",
        }));
      },
    }),
  },
});
displayNamestringOptional

Human-readable name shown in the control plane. Defaults to the connector’s filename identity when omitted.

descriptionstringOptional

What the connector provides. Surfaced to agents and operators.

instructionsstringOptional

Optional usage guidance forwarded to the agent alongside the connector’s tools.

toolsRecord<string, ConnectorToolDef>Optional

The tools this connector exposes. Each value is a defineTool definition; the key is the tool name the agent calls.

resourcesRecord<string, ConnectorResourceDef>Optional

MCP resources the connector serves. Optional.

promptsRecord<string, ConnectorPromptDef>Optional

MCP prompts the connector serves. Optional.

requiredEnvVarsreadonly string[]Optional

Environment variable names this connector reads at runtime (for example a third-party API key). The platform provisions only the declared keys to the connector from the agent’s configured environment; undeclared keys are never visible.

Note

Identity flows from the filesystem, never from a caller-supplied field. Declare requiredEnvVars here and set the values in the agent’s environment configuration — see Connectors.

#defineTool

defineTool describes a single tool. It accepts a Zod schema as input and infers the handler’s argument types from it, so the schema and the handler can never drift apart.

ts
import { defineConnector, defineTool } from "@kraken-ai/platform";
import * as z from "zod";

export default defineConnector({
  displayName: "Orakle",
  description: "Pricing intelligence for retail SKUs",
  requiredEnvVars: ["ORAKLE_API_KEY"],
  tools: {
    priceCheck: defineTool({
      description: "Look up a fair-market price band",
      input: z.object({ sku: z.string(), geo: z.string() }),
      handler: async ({ sku, geo }) => {
        // process.env.ORAKLE_API_KEY is provisioned by the platform
        // because it was declared in requiredEnvVars above.
        return fetchPrice(sku, geo, process.env.ORAKLE_API_KEY);
      },
    }),
  },
});
descriptionstringRequired

What the tool does. The agent uses this to decide when to call it.

inputz.ZodTypeRequired

A Zod schema describing the tool’s arguments. The handler’s parameter type is inferred from it, and the platform validates incoming arguments against it before the handler runs.

annotationsToolAnnotationsOptional

MCP tool hints — readOnlyHint, destructiveHint , idempotentHint, openWorldHint. Surfaced to governance and the agent.

handler(args) => Promise<Result> | ResultRequired

The function that runs the tool. May return a string, number, boolean, object, array, an mcpResult pass-through, or null/undefined.

#Result helpers

Handlers can return plain values — strings, objects, arrays — and the platform wraps them into MCP tool results for you. For full control over the MCP response, import the helpers from @kraken-ai/platform .

mcpResult(content, isError?)functionOptional

Build an explicit MCP content pass-through — for example a tool that returns an image alongside text, or a multi-part response marked as an error. Forwarded by the platform without modification.

wrapToolResult(value)functionOptional

Wrap any handler return value into MCP CallToolResult format. Primitives become text content; objects are serialized to JSON; mcpResult values pass through unchanged. Applied automatically by the connector server.

wrapToolError(error)functionOptional

Wrap a thrown error into an MCP error result. ConnectorError messages are forwarded to the agent as-is; all other errors become a generic internal-error message.

ConnectorErrorclassOptional

Throw this from a handler when the message is safe to show the agent (for example a validation or not-found message). Any other thrown error is masked.

ts
import { defineTool, mcpResult } from "@kraken-ai/platform";
import * as z from "zod";

const screenshot = defineTool({
  description: "Take a screenshot",
  input: z.object({ url: z.string().url() }),
  handler: async ({ url }) =>
    mcpResult([
      { type: "text", text: `Screenshot of ${url}` },
      { type: "image", data: base64png, mimeType: "image/png" },
    ]),
});

#Resources & prompts

Beyond tools, a connector can expose MCP resources — readable content addressed by URI — and MCP prompts — parameterized message templates. Provide them as the resources and prompts records on defineConnector. Each resource declares a required description, a uri, an optional mimeType, and a read handler; each prompt declares optional arguments and a get handler that returns the message list. Both are optional; most connectors only define tools.

#MCP & open standards

The Connector SDK builds on the Model Context Protocol, the open standard for connecting AI systems to external tools and data. There is no proprietary connector protocol: every MCP server is a connector, and a connector you define here is a standard MCP server.

Kraken’s value is the layer on top — governance, authentication, and health monitoring — not the protocol itself. Every tool call still passes through the governance gateway before it executes. See Open by Default for the reasoning, and Governance & Policies for how calls are authorized.

#Running a connector

During deployment the platform discovers and serves connectors for you. To run one standalone — for local testing or to host an MCP server outside a project — use startConnectorServer from @kraken-ai/platform/server. Because a standalone caller has no filesystem identity, you pass the connector’s name explicitly.

ts
import { startConnectorServer } from "@kraken-ai/platform/server";
import filesystem from "./connectors/filesystem";

const server = await startConnectorServer(filesystem, {
  name: "filesystem",
  port: 8080,
});

console.log(`Connector listening on port ${server.port}`);
// later: await server.close();

The server speaks MCP over streamable HTTP at /mcp and exposes a GET /health endpoint. Locally, kraken dev runs connectors for you — see the CLI reference.

#Next steps

  • Connectors — The conceptual model: how connectors feed agents, how identity works, and how MCP servers plug in.
  • Platform SDK — The PlatformClient and kraken CLI for running agents and managing credentials from your own code.
  • Governance & Policies — How every tool call is authorized, denied, or escalated to a human before it executes.