Guides

Add your first connector surfaces#

agent-connector starts after the neutral MCP server works. This page shows the first useful expansion path: declare the server, verify the install, then add host surfaces only when they solve a real user problem.

1. Use a staged expansion order#

Do not add every surface because it exists. Each surface answers a different question: what the model can call, what the host triggers, what the user invokes, what the host displays, and what context files it loads.

surface-order.txt
text
Plain MCP server works
  -> one host can call one read-only tool
  -> defineConnector({ server })
  -> install/doctor proves host config rendering
  -> add static surfaces when users need reusable context
  -> add hooks for lifecycle policy where hosts support hooks
  -> add statusline for glanceable state
  -> add actions for deliberate user commands

2. Start server-only#

The first connector config should only wrap the MCP server you already tested. That keeps install/doctor failures separate from hook or surface handler failures.

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

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

export default defineConnector({
  server: {
    transport: "stdio",
    command: "node",
    args: [serverPath],
  },
});

3. Add runtime surfaces deliberately#

Statusline and actions are runtime-dispatched handler surfaces. They are re-imported from the connector module, so keep handlers deterministic, fast, and safe to run without ambient process state.

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

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

const statusline = defineStatusline({
  description: "Show acme-db MCP usage state.",
  render(ctx) {
    const calls = ctx.usage?.calls ?? 0;
    return `acme-db: ${calls} tool calls`;
  },
});

const refreshIndex = defineAction({
  id: "refresh-index",
  description: "Refresh the local schema index.",
  async run(ctx) {
    return { message: `Refreshed schema index for ${ctx.host}` };
  },
});

export default defineConnector({
  server: { transport: "stdio", command: "node", args: [serverPath] },
  statusline,
  actions: [refreshIndex],
});

4. Choose by user need#

NeedSurfaceBeginner rule
The model should call a capabilityMCP toolKeep validation in the server.
The host lifecycle should add policy/contextHookTest one host per hook paradigm; MCP-only hosts skip hooks.
The human needs a compact state signalStatusline / HUDReturn short text; never block on network calls.
The human wants to trigger a commandActionUse clear command names and surface errors to the user.
Users repeat the same instructionsCommand, skill, subagent, or memoryPrefer static files for durable guidance; keep memory small.

5. Verify after each added surface#

  • Run install in one target host and read the generated diff or warning.
  • Run doctor before adding the next surface.
  • Confirm unsupported hosts skip with a warning instead of pretending the surface works.
  • Keep hard safety in the MCP tool handler; hooks and actions are not a substitute for server validation.