|
1 | 1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp" |
2 | 2 | import { CallToolResult } from "@modelcontextprotocol/sdk/types" |
3 | 3 | import z from "zod" |
4 | | -import { appCreate, appCreateChat, appDelete, appDeleteChat, appGetDefaultRooms, appGetDefaultRoomsWithAppId, appList, appTokensCreateV2, appTokensListV2, appTokensRevokeV2, appTokensRotateV2, appUpdate, apiPing, botGetV2, botUpdateV2, chatsBroadcastJobV2, chatsBroadcastV2, configureB2BToken, configureClient, filesDeleteV2, filesGetV2, filesUploadV2, getClientState, selectApp, setAuthMode, sourcesDocsDelete, sourcesDocsDeleteV2, sourcesDocsUpload, sourcesDocsUploadV2, sourcesSiteCrawl, sourcesSiteCrawlV2, sourcesSiteDeleteUrl, sourcesSiteDeleteUrlV2, sourcesSiteDeleteUrlV2Batch, sourcesSiteDeleteUrlV2Single, sourcesSiteReindex, sourcesSiteReindexV2, userLogin, userRegistration, usersBatchCreateJobV2, usersBatchCreateV2, walletERC20Transfer, walletGetBalance } from "./apiClientDappros.js" |
| 4 | +import { appCreate, appCreateChat, appDelete, appDeleteChat, appGetDefaultRooms, appGetDefaultRoomsWithAppId, appList, appProvisionV2, appTokensCreateV2, appTokensListV2, appTokensRevokeV2, appTokensRotateV2, appUpdate, apiPing, botGetV2, botUpdateV2, chatsBroadcastJobV2, chatsBroadcastV2, configureB2BToken, configureClient, filesDeleteV2, filesGetV2, filesUploadV2, getClientState, selectApp, setAuthMode, sourcesDocsDelete, sourcesDocsDeleteV2, sourcesDocsUpload, sourcesDocsUploadV2, sourcesSiteCrawl, sourcesSiteCrawlV2, sourcesSiteDeleteUrl, sourcesSiteDeleteUrlV2, sourcesSiteDeleteUrlV2Batch, sourcesSiteDeleteUrlV2Single, sourcesSiteReindex, sourcesSiteReindexV2, userLogin, userRegistration, usersBatchCreateJobV2, usersBatchCreateV2, walletERC20Transfer, walletGetBalance } from "./apiClientDappros.js" |
5 | 5 | import { fail, ok } from "./mcpResponse.js" |
6 | 6 |
|
7 | 7 | function errorToText(error: unknown) { |
@@ -2252,6 +2252,94 @@ function appTokensRevokeV2Tool(server: McpServer) { |
2252 | 2252 | ) |
2253 | 2253 | } |
2254 | 2254 |
|
| 2255 | +function b2bAppProvisionTool(server: McpServer) { |
| 2256 | + server.registerTool( |
| 2257 | + "ethora-b2b-app-provision", |
| 2258 | + { |
| 2259 | + description: "One-call B2B flow: create app → create one or more app tokens → provision default rooms → configure/enable bot.", |
| 2260 | + inputSchema: { |
| 2261 | + displayName: z.string().min(1).describe("New app display name"), |
| 2262 | + // tokens |
| 2263 | + tokenLabels: z.array(z.string().min(1)).min(1).max(5).optional().describe("Optional labels for new tokens. Default: ['default']"), |
| 2264 | + // rooms |
| 2265 | + rooms: z.array(z.object({ |
| 2266 | + title: z.string().min(1), |
| 2267 | + pinned: z.boolean().optional(), |
| 2268 | + })).max(20).optional().describe("Optional default rooms to create (B2B)."), |
| 2269 | + // bot |
| 2270 | + enableBot: z.boolean().optional().describe("If true, enables bot (app-token auth using first created token)."), |
| 2271 | + botTrigger: z.enum(["any_message", "/bot"]).optional(), |
| 2272 | + botPrompt: z.string().optional(), |
| 2273 | + botGreetingMessage: z.string().optional(), |
| 2274 | + }, |
| 2275 | + }, |
| 2276 | + async function ({ displayName, tokenLabels, rooms, enableBot, botTrigger, botPrompt, botGreetingMessage }) { |
| 2277 | + const meta = getDefaultMeta("ethora-b2b-app-provision") |
| 2278 | + const prev = (getClientState() as any).authMode as any |
| 2279 | + try { |
| 2280 | + ensureB2BAuthForTool() |
| 2281 | + |
| 2282 | + const steps: any[] = [] |
| 2283 | + |
| 2284 | + // 1) Create app (B2B) |
| 2285 | + setAuthMode("b2b") |
| 2286 | + const created = await appCreate(displayName) |
| 2287 | + const app = created?.data?.app |
| 2288 | + const appId = String(app?._id || app?.id || "").trim() |
| 2289 | + if (!appId) throw new Error("Create app succeeded but no appId found in response") |
| 2290 | + steps.push({ step: "appCreate", ok: true, appId }) |
| 2291 | + |
| 2292 | + // 2) Create tokens (B2B) |
| 2293 | + const labels = Array.isArray(tokenLabels) && tokenLabels.length ? tokenLabels : ["default"] |
| 2294 | + const createdTokens: any[] = [] |
| 2295 | + for (const label of labels) { |
| 2296 | + const r = await appTokensCreateV2(appId, { label }, { timeoutMs: 10_000 }) |
| 2297 | + createdTokens.push(r.data) |
| 2298 | + } |
| 2299 | + const primaryToken = String(createdTokens?.[0]?.token || "").trim() |
| 2300 | + steps.push({ step: "appTokensCreate", ok: true, count: createdTokens.length }) |
| 2301 | + |
| 2302 | + // 3) Provision rooms (B2B) |
| 2303 | + let provisionRes: any = null |
| 2304 | + if (Array.isArray(rooms) && rooms.length) { |
| 2305 | + const r = await appProvisionV2(appId, { rooms }, { timeoutMs: 60_000 }) |
| 2306 | + provisionRes = r.data |
| 2307 | + steps.push({ step: "appProvisionRooms", ok: true, requested: rooms.length }) |
| 2308 | + } |
| 2309 | + |
| 2310 | + // 4) Configure bot (app-token using first created token) |
| 2311 | + let botRes: any = null |
| 2312 | + if (enableBot || botTrigger || botPrompt || botGreetingMessage) { |
| 2313 | + if (!primaryToken) throw new Error("Bot config requested but no app token was created") |
| 2314 | + selectApp({ appId, appToken: primaryToken, authMode: "app" }) |
| 2315 | + setAuthMode("app") |
| 2316 | + const payload: any = {} |
| 2317 | + if (enableBot) payload.status = "on" |
| 2318 | + if (botTrigger) payload.trigger = botTrigger |
| 2319 | + if (botPrompt) payload.prompt = botPrompt |
| 2320 | + if (botGreetingMessage) payload.greetingMessage = botGreetingMessage |
| 2321 | + const r = await botUpdateV2(payload) |
| 2322 | + botRes = r.data |
| 2323 | + steps.push({ step: "botUpdateV2", ok: true }) |
| 2324 | + } |
| 2325 | + |
| 2326 | + return asToolResult(ok({ |
| 2327 | + appId, |
| 2328 | + app, |
| 2329 | + tokens: createdTokens, |
| 2330 | + provision: provisionRes, |
| 2331 | + bot: botRes, |
| 2332 | + steps, |
| 2333 | + state: getClientState(), |
| 2334 | + }, meta)) |
| 2335 | + } catch (error) { |
| 2336 | + try { setAuthMode(prev) } catch (_) {} |
| 2337 | + return asToolResult(fail(error, meta)) |
| 2338 | + } |
| 2339 | + } |
| 2340 | + ) |
| 2341 | +} |
| 2342 | + |
2255 | 2343 | function sourcesSiteDeleteUrlV2AppTool(server: McpServer) { |
2256 | 2344 | server.registerTool( |
2257 | 2345 | "ethora-sources-site-delete-url-v2", |
@@ -2385,6 +2473,7 @@ export function registerTools(server: McpServer) { |
2385 | 2473 | appTokensCreateV2Tool(server); |
2386 | 2474 | appTokensRotateV2Tool(server); |
2387 | 2475 | appTokensRevokeV2Tool(server); |
| 2476 | + b2bAppProvisionTool(server); |
2388 | 2477 | userLoginWithEmailTool(server); |
2389 | 2478 | userRegisterWithEmailTool(server); |
2390 | 2479 | appListTool(server); |
|
0 commit comments