Skip to content
Merged
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
13 changes: 13 additions & 0 deletions apps/cluster/migrations/0060_chat_mcp_servers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- The MCP servers chat turns can use, configured on the dashboard (EFF-3443).
-- No secret is stored here: bearer tokens and OAuth state stay in each
-- server's credential Durable Object, named by the server's id.
CREATE TABLE chat_mcp_servers (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE CHECK (name ~ '^[a-z0-9_]{1,32}$'),
url TEXT NOT NULL CHECK (url LIKE 'https://%'),
auth TEXT NOT NULL CHECK (auth IN ('none', 'bearer', 'oauth')),
private BOOLEAN NOT NULL DEFAULT TRUE,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT CLOCK_TIMESTAMP()
);
1 change: 1 addition & 0 deletions apps/cluster/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@effect/platform-node": "catalog:",
"@effect/sql-pg": "catalog:",
"@janitor/domain": "workspace:^",
"@modelcontextprotocol/sdk": "catalog:",
"alchemy": "catalog:",
"clanka": "catalog:",
"dfx": "catalog:",
Expand Down
9 changes: 8 additions & 1 deletion apps/cluster/src/Chat/Agent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Agent from "clanka/Agent"
import type * as AgentExecutor from "clanka/AgentExecutor"
import type * as AgentOutput from "clanka/AgentOutput"
import type * as McpServers from "clanka/McpServers"
import type * as AiError from "effect/ai/AiError"
import * as LanguageModel from "effect/ai/LanguageModel"
import * as Model from "effect/ai/Model"
Expand Down Expand Up @@ -79,6 +80,8 @@ export interface ChatTurnStart {
readonly onProgress: (progress: ChatProgress) => Effect.Effect<void>
/** The `attachFile` tool: succeeds or fails with what the model is told. */
readonly attachFile: (input: typeof AttachFileParameters.Type) => Effect.Effect<string, string>
/** MCP servers the loop and its sub-agents get, connected for the loop's lifetime. */
readonly mcp?: Layer.Layer<McpServers.McpServers> | undefined
}

/** An attached image the model sees with the prompt. */
Expand Down Expand Up @@ -239,7 +242,11 @@ const make = Effect.gen(function* () {
}).pipe(
Effect.scoped,
Effect.provide(
Layer.merge(options.executor, ChatTools.toLayer({ attachFile: options.attachFile })),
Layer.mergeAll(
options.executor,
ChatTools.toLayer({ attachFile: options.attachFile }),
options.mcp ?? Layer.empty,
),
),
Effect.provideContext(model),
Option.isSome(subagentModel)
Expand Down
Loading