Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
"packages/appkit/src/plugins/vector-search/**",
"packages/appkit/src/plugin/index.ts",
"packages/appkit/src/plugins/agents/index.ts",
"packages/appkit/src/plugins/agents/tools/index.ts",
"packages/appkit/src/plugins/agents/from-plugin.ts",
"packages/appkit/src/plugins/agents/load-agents.ts",
"template/**",
"tools/**",
"docs/**"
"docs/**",
"packages/appkit/src/core/agent/tools/index.ts",
"packages/appkit/src/core/agent/from-plugin.ts",
"packages/appkit/src/core/agent/load-agents.ts",
"packages/appkit/src/connectors/mcp/index.ts",
"packages/appkit/src/plugin/to-plugin.ts"
],
"ignoreDependencies": ["json-schema-to-typescript"],
"ignoreBinaries": ["tarball"]
Expand Down
3 changes: 2 additions & 1 deletion packages/appkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
"semver": "7.7.3",
"shared": "workspace:*",
"vite": "npm:rolldown-vite@7.1.14",
"ws": "8.18.3"
"ws": "8.18.3",
"zod": "^4.0.0"
},
"devDependencies": {
"@types/express": "4.17.25",
Expand Down
1 change: 1 addition & 0 deletions packages/appkit/src/connectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from "./files";
export * from "./genie";
export * from "./lakebase";
export * from "./lakebase-v1";
export * from "./mcp";
export * from "./sql-warehouse";
export * from "./vector-search";
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@
* transport.
*/
import type { AgentToolDefinition } from "shared";
import { createLogger } from "../../../logging/logger";
import type { McpEndpointConfig } from "../../../core/agent/tools/hosted-tools";
import { createLogger } from "../../logging/logger";
import {
assertResolvedHostSafe,
checkMcpUrl,
type DnsLookup,
type McpHostPolicy,
} from "./mcp-host-policy";
} from "./host-policy";
import type { McpEndpointConfig } from "./types";

const logger = createLogger("agent:mcp");
const logger = createLogger("connector:mcp");

interface JsonRpcRequest {
jsonrpc: "2.0";
Expand Down
6 changes: 6 additions & 0 deletions packages/appkit/src/connectors/mcp/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export { AppKitMcpClient } from "./client";
export {
buildMcpHostPolicy,
type McpHostPolicyConfig,
} from "./host-policy";
export type { McpEndpointConfig } from "./types";
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, test, vi } from "vitest";
import { AppKitMcpClient } from "../tools/mcp-client";
import type { DnsLookup, McpHostPolicy } from "../tools/mcp-host-policy";
import { AppKitMcpClient } from "../client";
import type { DnsLookup, McpHostPolicy } from "../host-policy";

const WORKSPACE = "https://test-workspace.cloud.databricks.com";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
isLoopbackHost,
type McpHostPolicy,
type McpHostPolicyConfig,
} from "../tools/mcp-host-policy";
} from "../host-policy";

function stubLookup(
addresses: Array<{ address: string; family?: number }>,
Expand Down
12 changes: 12 additions & 0 deletions packages/appkit/src/connectors/mcp/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Input shape consumed by {@link AppKitMcpClient.connect}. Produced by the
* agents plugin from user-facing `HostedTool` declarations (see
* `plugins/agents/tools/hosted-tools.ts`) and accepted directly by the
* connector to keep its surface free of agent-layer concepts.
*/
export interface McpEndpointConfig {
/** Stable logical name used as the `mcp.<name>.*` tool prefix and in logs. */
name: string;
/** Absolute URL (`https://…`) or workspace-relative path (`/api/2.0/mcp/…`). */
url: string;
}
53 changes: 53 additions & 0 deletions packages/appkit/src/core/agent/create-agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ConfigurationError } from "../../errors";
import type { AgentDefinition } from "./types";

/**
* Pure factory for agent definitions. Returns the passed-in definition after
* cycle-detecting the sub-agent graph. Accepts the full `AgentDefinition` shape
* and is safe to call at module top-level.
*
* The returned value is a plain `AgentDefinition` — no adapter construction,
* no side effects. Register it with `agents({ agents: { name: def } })` or run
* it standalone via `runAgent(def, input)`.
*
* @example
* ```ts
* const support = createAgent({
* instructions: "You help customers.",
* model: "databricks-claude-sonnet-4-5",
* tools: {
* get_weather: tool({ ... }),
* },
* });
* ```
*/
export function createAgent(def: AgentDefinition): AgentDefinition {
detectCycles(def);
return def;
}

/**
* Walks the `agents: { ... }` sub-agent tree via DFS and throws if a cycle is
* found. Cycles would cause infinite recursion at tool-invocation time.
*/
function detectCycles(def: AgentDefinition): void {
const visiting = new Set<AgentDefinition>();
const visited = new Set<AgentDefinition>();

const walk = (current: AgentDefinition, path: string[]): void => {
if (visited.has(current)) return;
if (visiting.has(current)) {
throw new ConfigurationError(
`Agent sub-agent cycle detected: ${path.join(" -> ")}`,
);
}
visiting.add(current);
for (const [childKey, child] of Object.entries(current.agents ?? {})) {
walk(child, [...path, childKey]);
}
visiting.delete(current);
visited.add(current);
};

walk(def, [def.name ?? "(root)"]);
}
Loading