Getting Started

SDK overview#

The SDK is the framework surface for MCP-package authors. Your package owns the public identity and binary; agent-connector supplies the authoring API, host adapters, installer, doctor, telemetry wrapper, and packaging machinery underneath that brand.

Package identity is the source of truth#

In the normal path, do not ask for a separate connector id, display name, binary name, or version. Those values already exist in your package metadata. package.json name / mcpName identify the MCP server, bin names the command users run, and version becomes the connector version. Override fields in defineConnector only for legacy configs or deliberate multi-instance aliases.

package.json
json
{
  "name": "@acme/acme-db-mcp",
  "version": "1.0.0",
  "type": "module",
  "mcpName": "io.github.acme/acme-db",
  "bin": {
    "acme-db": "./bin.mjs"
  },
  "dependencies": {
    "@ken-jo/agent-connector": "^0.4.94"
  }
}

Authoring imports#

New connector packages should reach for @ken-jo/agent-connector/sdk. It re-exports defineConnector, the typed define* identity helpers for individual surfaces, host capability helpers such as hostsSupporting, and the public types. The root package export remains available, but /sdk is the consolidated authoring entry point.

agent-connector.config.mjs
ts
import {
  defineConnector,
  defineHook,
  defineMemory,
  hostsSupporting,
} from "@ken-jo/agent-connector/sdk";

export const confirmWrites = defineHook("PreToolUse", {
  matcher: "acme_write",
  handler(evt) {
    return evt.toolName === "acme_write"
      ? { decision: "ask", reason: "Confirm Acme DB write" }
      : { decision: "allow" };
  },
});

export const acmeGuidance = defineMemory({
  name: "acme-db-guidance",
  content: "Prefer readonly Acme DB tools unless the user asks to mutate data.",
});

export default defineConnector({
  hooks: { PreToolUse: confirmWrites },
  memory: [acmeGuidance],
});

const hookHosts = await hostsSupporting("hooks");

MCP server launch shapes#

Not every MCP starts the same way. A package-runner MCP can launch with npx -y <package>, a local Node/process MCP can launch with node <server-file>, a Python MCP should usually launch with uv run --with mcp <server.py>, a CLI-based MCP can launch an existing executable, and a remote server MCP should use HTTP transport. In all cases, keep the wrapper package's package.json as the public identity and point the server block at the real MCP process or URL.

agent-connector.config.mjs
ts
import { fileURLToPath } from "node:url";
import { defineConnector } from "@ken-jo/agent-connector/sdk";

const localServerPath = fileURLToPath(
  new URL("./my-mcp-server.mjs", import.meta.url),
);

const serverShapes = {
  packageRunner: {
    transport: "stdio",
    command: "npx",
    args: ["-y", "@acme/acme-db-mcp"],
  },
  localProcess: {
    transport: "stdio",
    command: "node",
    args: [localServerPath],
  },
  pythonProcess: {
    transport: "stdio",
    command: "uv",
    args: ["run", "--with", "mcp", "./my_mcp_server.py"],
  },
  cliBased: {
    transport: "stdio",
    command: "local-tools",
    args: ["mcp", "serve"],
  },
  remoteServer: {
    transport: "http",
    url: "https://mcp.example.com/mcp",
  },
} as const;

export default defineConnector({
  // Choose the one server shape that matches the MCP you are building.
  // package.json still owns public identity: name, mcpName, bin, version.
  server: serverShapes.packageRunner,
});

How the framework wires it

package.json supplies public identity. Your bin.mjs wraps createConnectorCli under that brand. defineConnector points at the real MCP process or URL. Install then renders native host config from that single declaration. Stdio processes can be launched through the stable home binary for per-tool telemetry; remote HTTP servers are registered by URL where the host supports them.

CLI boundary#

@ken-jo/agent-connector/cli is a separate boundary: use createConnectorCli in your package's bin so users run your command, for example acme-db install or npx @acme/acme-db-mcp install. The framework CLI remains useful for framework development and connector-free usage telemetry, not as the foreground installer brand for your MCP package.

bin.mjs
ts
#!/usr/bin/env node
// bin.mjs — your package.json "bin" target, e.g. "acme-db"
import { createConnectorCli } from "@ken-jo/agent-connector/cli";

// run() resolves to the exit code and never calls process.exit — forward it.
process.exitCode = await createConnectorCli({
  // packageJson supplies public identity: name, mcpName, bin, version.
  packageJson: new URL("./package.json", import.meta.url),
  // connector supplies behavior: server, hooks, skills, telemetry.
  // These are two layers, not duplicate id/display-name inputs.
  connector: new URL("./agent-connector.config.mjs", import.meta.url),
}).run();

What the framework can audit#

Because package metadata and defineConnector are both structured,audit can verify that the package identity, branded bin, install command, MCP server command, runtime dependency, and rendered host aliases stay aligned before users install anything. In a branded package that means acme-db audit; from the framework CLI it is agent-connector audit --connector ./agent-connector.config.mjs. That audit surface is why the SDK keeps identity in one place instead of asking the wizard or docs reader to duplicate it.

Framework first in code, brand first for users

Developers install @ken-jo/agent-connector as a dependency. Users install or run your MCP package. Connector-free token telemetry is the exception where the framework package can be used directly.

Agent-ready references#

Most connector packages will be scaffolded, reviewed, and repaired by AI agents. The repo therefore ships machine-readable and skill-friendly references: llms.txt for the short route map, llms-full.txt for the exhaustive contract, and skills/agent-connector/SKILL.md as a small router into focused files under skills/agent-connector/references/. Agents should read only the reference they need, then validate with SDK offline harnesses, dry-run install plans, and doctor --probe when a real stdio server is available.

This mirrors the pattern used by agent-ready toolchains such as shadcn/ui: keep a compact LLM map, read structured project config before generating code, expose a small skill entry point, and reserve deeper reference files for task-specific detail.