diff --git a/apps/docs-autorag/src/context.ts b/apps/docs-autorag/src/context.ts index 73217c6e..85ef234e 100644 --- a/apps/docs-autorag/src/context.ts +++ b/apps/docs-autorag/src/context.ts @@ -3,8 +3,8 @@ import type { CloudflareDocumentationMCP } from './index' export interface Env { ENVIRONMENT: 'development' | 'staging' | 'production' AUTORAG_NAME: 'cloudflare-docs-autorag' - MCP_SERVER_NAME: 'PLACEHOLDER' - MCP_SERVER_VERSION: 'PLACEHOLDER' + MCP_SERVER_NAME: string + MCP_SERVER_VERSION: string MCP_OBJECT: DurableObjectNamespace MCP_METRICS: AnalyticsEngineDataset AI: Ai diff --git a/apps/sandbox-container/server/context.ts b/apps/sandbox-container/server/context.ts index 8542514e..83829b35 100644 --- a/apps/sandbox-container/server/context.ts +++ b/apps/sandbox-container/server/context.ts @@ -2,11 +2,11 @@ import type { ContainerManager, ContainerMcpAgent } from './index' export interface Env { OAUTH_KV: KVNamespace - CLOUDFLARE_CLIENT_ID: '' - CLOUDFLARE_CLIENT_SECRET: '' + CLOUDFLARE_CLIENT_ID: string + CLOUDFLARE_CLIENT_SECRET: string ENVIRONMENT: 'dev' - MCP_SERVER_NAME: '' - MCP_SERVER_VERSION: '' + MCP_SERVER_NAME: string + MCP_SERVER_VERSION: string OPENAI_API_KEY: string CONTAINER_MCP_AGENT: DurableObjectNamespace CONTAINER_MANAGER: DurableObjectNamespace diff --git a/apps/workers-bindings/src/context.ts b/apps/workers-bindings/src/context.ts index 0617c015..e37a249b 100644 --- a/apps/workers-bindings/src/context.ts +++ b/apps/workers-bindings/src/context.ts @@ -1,12 +1,14 @@ +import type { UserDetails } from '@repo/mcp-common/src/durable-objects/user_details' import type { WorkersBindingsMCP } from './index' export interface Env { OAUTH_KV: KVNamespace ENVIRONMENT: 'development' | 'staging' | 'production' - MCP_SERVER_NAME: '' - MCP_SERVER_VERSION: '' - CLOUDFLARE_CLIENT_ID: '' - CLOUDFLARE_CLIENT_SECRET: '' + MCP_SERVER_NAME: string + MCP_SERVER_VERSION: string + CLOUDFLARE_CLIENT_ID: string + CLOUDFLARE_CLIENT_SECRET: string MCP_OBJECT: DurableObjectNamespace + USER_DETAILS: DurableObjectNamespace MCP_METRICS: AnalyticsEngineDataset } diff --git a/apps/workers-bindings/src/index.ts b/apps/workers-bindings/src/index.ts index 08a70df8..0db32651 100644 --- a/apps/workers-bindings/src/index.ts +++ b/apps/workers-bindings/src/index.ts @@ -5,6 +5,7 @@ import { createAuthHandlers, handleTokenExchangeCallback, } from '@repo/mcp-common/src/cloudflare-oauth-handler' +import { getUserDetails, UserDetails } from '@repo/mcp-common/src/durable-objects/user_details' import { getEnv } from '@repo/mcp-common/src/env' import { RequiredScopes } from '@repo/mcp-common/src/scopes' import { CloudflareMCPServer } from '@repo/mcp-common/src/server' @@ -18,6 +19,8 @@ import { MetricsTracker } from '@repo/mcp-observability' import type { AccountSchema, UserSchema } from '@repo/mcp-common/src/cloudflare-oauth-handler' import type { Env } from './context' +export { UserDetails } + const env = getEnv() const metrics = new MetricsTracker(env.MCP_METRICS, { @@ -73,24 +76,25 @@ export class WorkersBindingsMCP extends McpAgent + USER_DETAILS: DurableObjectNamespace MCP_METRICS: AnalyticsEngineDataset - SENTRY_ACCESS_CLIENT_ID: 'PLACEHOLDER' - SENTRY_ACCESS_CLIENT_SECRET: 'PLACEHOLDER' - GIT_HASH: 'OVERRIDEN_DURING_DEPLOYMENT' - SENTRY_DSN: 'PLACEHOLDER' + SENTRY_ACCESS_CLIENT_ID: string + SENTRY_ACCESS_CLIENT_SECRET: string + GIT_HASH: string + SENTRY_DSN: string } diff --git a/apps/workers-observability/src/index.ts b/apps/workers-observability/src/index.ts index 6a61e991..d5fd29fb 100644 --- a/apps/workers-observability/src/index.ts +++ b/apps/workers-observability/src/index.ts @@ -5,6 +5,7 @@ import { createAuthHandlers, handleTokenExchangeCallback, } from '@repo/mcp-common/src/cloudflare-oauth-handler' +import { getUserDetails, UserDetails } from '@repo/mcp-common/src/durable-objects/user_details' import { getEnv } from '@repo/mcp-common/src/env' import { RequiredScopes } from '@repo/mcp-common/src/scopes' import { initSentryWithUser } from '@repo/mcp-common/src/sentry' @@ -18,6 +19,8 @@ import { registerLogsTools } from './tools/logs' import type { AccountSchema, UserSchema } from '@repo/mcp-common/src/cloudflare-oauth-handler' import type { Env } from './context' +export { UserDetails } + const env = getEnv() const metrics = new MetricsTracker(env.MCP_METRICS, { @@ -72,26 +75,24 @@ export class ObservabilityMCP extends McpAgent { registerLogsTools(this) } - getActiveAccountId() { - // TODO: Figure out why this fail sometimes, and why we need to wrap this in a try catch + async getActiveAccountId() { try { - return this.state.activeAccountId ?? null + // Get UserDetails Durable Object based off the userId and retrieve the activeAccountId from it + // we do this so we can persist activeAccountId across sessions + const userDetails = getUserDetails(env, this.props.user.id) + return await userDetails.getActiveAccountId() } catch (e) { this.server.recordError(e) return null } } - setActiveAccountId(accountId: string) { - // TODO: Figure out why this fail sometimes, and why we need to wrap this in a try catch + async setActiveAccountId(accountId: string) { try { - this.setState({ - ...this.state, - activeAccountId: accountId, - }) + const userDetails = getUserDetails(env, this.props.user.id) + await userDetails.setActiveAccountId(accountId) } catch (e) { this.server.recordError(e) - return null } } } diff --git a/apps/workers-observability/src/tools/logs.ts b/apps/workers-observability/src/tools/logs.ts index 8fa723b2..ef4bf763 100644 --- a/apps/workers-observability/src/tools/logs.ts +++ b/apps/workers-observability/src/tools/logs.ts @@ -123,7 +123,7 @@ export function registerLogsTools(agent: ObservabilityMCP) { rayId: rayIdParam, }, async (params) => { - const accountId = agent.getActiveAccountId() + const accountId = await agent.getActiveAccountId() if (!accountId) { return { content: [ @@ -188,7 +188,7 @@ export function registerLogsTools(agent: ObservabilityMCP) { minutesAgoParam, }, async (params) => { - const accountId = agent.getActiveAccountId() + const accountId = await agent.getActiveAccountId() if (!accountId) { return { content: [ @@ -248,7 +248,7 @@ export function registerLogsTools(agent: ObservabilityMCP) { 'Get available telemetry keys for a Cloudflare Worker', { scriptName: workerNameParam, minutesAgoParam }, async (params) => { - const accountId = agent.getActiveAccountId() + const accountId = await agent.getActiveAccountId() if (!accountId) { return { content: [ diff --git a/apps/workers-observability/wrangler.jsonc b/apps/workers-observability/wrangler.jsonc index b8417efe..078f34ce 100644 --- a/apps/workers-observability/wrangler.jsonc +++ b/apps/workers-observability/wrangler.jsonc @@ -10,7 +10,7 @@ "name": "mcp-cloudflare-workers-observability-dev", "migrations": [ { - "new_sqlite_classes": ["ObservabilityMCP"], + "new_sqlite_classes": ["UserDetails", "ObservabilityMCP"], "tag": "v1" } ], @@ -22,6 +22,10 @@ { "class_name": "ObservabilityMCP", "name": "MCP_OBJECT" + }, + { + "class_name": "UserDetails", + "name": "USER_DETAILS" } ] }, @@ -59,6 +63,10 @@ { "class_name": "ObservabilityMCP", "name": "MCP_OBJECT" + }, + { + "class_name": "UserDetails", + "name": "USER_DETAILS" } ] }, @@ -72,7 +80,7 @@ "ENVIRONMENT": "staging", "GIT_HASH": "OVERRIDEN_DURING_DEPLOYMENT", "SENTRY_DSN": "https://033e673c1b004626609d9a68a8b86b56@sentry10.cfdata.org/1764", - "MCP_SERVER_NAME": "workers-staging-observability", + "MCP_SERVER_NAME": "workers-observability-staging", "MCP_SERVER_VERSION": "1.0.0" }, "analytics_engine_datasets": [ @@ -91,6 +99,10 @@ { "class_name": "ObservabilityMCP", "name": "MCP_OBJECT" + }, + { + "class_name": "UserDetails", + "name": "USER_DETAILS" } ] }, diff --git a/packages/mcp-common/src/durable-kv-store.ts b/packages/mcp-common/src/durable-kv-store.ts new file mode 100644 index 00000000..66858699 --- /dev/null +++ b/packages/mcp-common/src/durable-kv-store.ts @@ -0,0 +1,112 @@ +import type { ZodSchema } from 'zod' + +export type DurableKVStorageKeys = { [key: string]: ZodSchema } + +/** + * DurableKVStore is a type-safe key/value store backed by Durable Object storage. + * + * @example + * + * ```ts + * export class MyDurableObject extends DurableObject { + * readonly kv + * constructor( + * readonly state: DurableObjectState, + * env: Bindings + * ) { + * super(state, env) + * this.kv = new DurableKVStore({ + * state, + * prefix: 'meta', + * keys: { + * // Each key has a matching Zod schema enforcing what's stored + * date_key: z.coerce.date(), + * // While empty keys will always return null, adding + * // `nullable()` allows us to explicitly set it to null + * string_key: z.string().nullable(), + * number_key: z.number(), + * } as const satisfies StorageKeys, + * }) + * } + * + * async example(): Promise { + * await this.kv.get('number_key') // -> null + * this.kv.put('number_key', 5) + * await this.kv.get('number_key') // -> 5 + * } + * } + * ``` + */ +export class DurableKVStore { + private readonly prefix: string + private readonly keys: T + private readonly state: DurableObjectState + + constructor({ state, prefix, keys }: { state: DurableObjectState; prefix: string; keys: T }) { + this.state = state + this.prefix = prefix + this.keys = keys + } + + /** Add the prefix to a key (used for get/put operations) */ + private addPrefix(key: K): string { + if (this.prefix.length > 0) { + return `${this.prefix}/${key.toString()}` + } + return key.toString() + } + + /** + * Get a value from KV storage. Returns `null` if the value + * is not set (or if it's explicitly set to `null`) + */ + async get(key: K): Promise + /** + * Get a value from KV storage or return the provided + * default if they value in storage is unset (undefined). + * The default value must match the schema for the given key. + * + * If defaultValue is explicitly set to undefined, it will still return null (avoid this). + * + * If the value in storage is null then this will return null instead of the default. + */ + async get(key: K, defaultValue: T[K]['_output']): Promise + async get( + key: K, + defaultValue?: T[K]['_output'] + ): Promise { + const schema = this.keys[key] + if (schema === undefined) { + throw new TypeError(`key ${key.toString()} has no matching schema`) + } + + const res = await this.state.storage.get(this.addPrefix(key)) + if (res === undefined) { + if (defaultValue !== undefined) { + return schema.parse(defaultValue) + } + return null + } + + return schema.parse(res) + } + + /** Write value to KV storage */ + put(key: K, value: T[K]['_input']): void { + const schema = this.keys[key] + if (schema === undefined) { + throw new TypeError(`key ${key.toString()} has no matching schema`) + } + const parsedValue = schema.parse(value) + void this.state.storage.put(this.addPrefix(key), parsedValue) + } + + /** + * Delete value in KV storage. **Does not need to be awaited** + * + * @returns `true` if a value was deleted, or `false` if it did not. + */ + async delete(key: K): Promise { + return this.state.storage.delete(this.addPrefix(key)) + } +} diff --git a/packages/mcp-common/src/durable-objects/user_details.ts b/packages/mcp-common/src/durable-objects/user_details.ts new file mode 100644 index 00000000..b9796dd5 --- /dev/null +++ b/packages/mcp-common/src/durable-objects/user_details.ts @@ -0,0 +1,45 @@ +import { DurableObject } from 'cloudflare:workers' +import { z } from 'zod' + +import { DurableKVStore } from '../durable-kv-store' + +import type { DurableKVStorageKeys } from '../durable-kv-store' + +// Durable Object for persisting UserDetails in DO storage across sessions based off the userId +export class UserDetails extends DurableObject { + private readonly kv: DurableKVStore + constructor(state: DurableObjectState, env: unknown) { + super(state, env) + this.env = env + this.kv = new DurableKVStore({ + state, + prefix: 'meta', + keys: UserDetailsKeys, + }) + } + + public async getActiveAccountId() { + return await this.kv.get('active_account_id') + } + + public async setActiveAccountId(activeAccountId: string) { + this.kv.put('active_account_id', activeAccountId) + } +} + +/** + * Storage keys used by UserDetails + */ +type UserDetailsKeys = typeof UserDetailsKeys +const UserDetailsKeys = { + active_account_id: z.string(), +} as const satisfies DurableKVStorageKeys + +/** Get the UserDetails instance */ +export function getUserDetails( + env: { USER_DETAILS: DurableObjectNamespace }, + user_id: string +): DurableObjectStub { + const id = env.USER_DETAILS.idFromName(user_id) + return env.USER_DETAILS.get(id) +} diff --git a/packages/mcp-common/src/env.ts b/packages/mcp-common/src/env.ts index b86badc3..00a223ff 100644 --- a/packages/mcp-common/src/env.ts +++ b/packages/mcp-common/src/env.ts @@ -1,6 +1,6 @@ import { env } from 'cloudflare:workers' // Helper to cast env as any generic Env type -export function getEnv() { - return env as T +export function getEnv() { + return env as Env } diff --git a/packages/mcp-common/src/tools/account.ts b/packages/mcp-common/src/tools/account.ts index 493d2474..b4360a33 100644 --- a/packages/mcp-common/src/tools/account.ts +++ b/packages/mcp-common/src/tools/account.ts @@ -58,7 +58,7 @@ export function registerAccountTools(agent: CloudflareMcpAgent) { async (params) => { try { const { activeAccountIdParam: activeAccountId } = params - agent.setActiveAccountId(activeAccountId) + await agent.setActiveAccountId(activeAccountId) return { content: [ { diff --git a/packages/mcp-common/src/tools/d1.ts b/packages/mcp-common/src/tools/d1.ts index 9b217e52..0e8878fd 100644 --- a/packages/mcp-common/src/tools/d1.ts +++ b/packages/mcp-common/src/tools/d1.ts @@ -21,7 +21,7 @@ export function registerD1Tools(agent: CloudflareMcpAgent) { per_page: PaginationPerPageParam, }, async ({ name, page, per_page }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -66,7 +66,7 @@ export function registerD1Tools(agent: CloudflareMcpAgent) { primary_location_hint: D1DatabasePrimaryLocationHintParam.nullable().optional(), }, async ({ name, primary_location_hint }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -104,7 +104,7 @@ export function registerD1Tools(agent: CloudflareMcpAgent) { 'Delete a d1 database in your Cloudflare account', { database_id: z.string() }, async ({ database_id }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -139,7 +139,7 @@ export function registerD1Tools(agent: CloudflareMcpAgent) { 'Get a D1 database in your Cloudflare account', { database_id: z.string() }, async ({ database_id }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -179,7 +179,7 @@ export function registerD1Tools(agent: CloudflareMcpAgent) { params: D1DatabaseQueryParamsParam.nullable(), }, async ({ database_id, sql, params }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } diff --git a/packages/mcp-common/src/tools/kv_namespace.ts b/packages/mcp-common/src/tools/kv_namespace.ts index 4ec711ef..58cdf66b 100644 --- a/packages/mcp-common/src/tools/kv_namespace.ts +++ b/packages/mcp-common/src/tools/kv_namespace.ts @@ -16,7 +16,7 @@ export function registerKVTools(agent: CloudflareMcpAgent) { 'List all of the kv namespaces in your Cloudflare account', { params: KvNamespacesListParamsSchema.optional() }, async ({ params }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -63,7 +63,7 @@ export function registerKVTools(agent: CloudflareMcpAgent) { title: KvNamespaceTitleSchema, }, async ({ title }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -101,7 +101,7 @@ export function registerKVTools(agent: CloudflareMcpAgent) { namespace_id: KvNamespaceIdSchema, }, async ({ namespace_id }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -139,7 +139,7 @@ export function registerKVTools(agent: CloudflareMcpAgent) { namespace_id: KvNamespaceIdSchema, }, async ({ namespace_id }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -178,7 +178,7 @@ export function registerKVTools(agent: CloudflareMcpAgent) { title: KvNamespaceTitleSchema, }, async ({ namespace_id, title }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } diff --git a/packages/mcp-common/src/tools/r2_bucket.ts b/packages/mcp-common/src/tools/r2_bucket.ts index fb200173..84579f68 100644 --- a/packages/mcp-common/src/tools/r2_bucket.ts +++ b/packages/mcp-common/src/tools/r2_bucket.ts @@ -22,7 +22,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { start_after: BucketListStartAfterParam, }, async ({ cursor, direction, name_contains, per_page, start_after }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -66,7 +66,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { 'Create a new r2 bucket in your Cloudflare account', { name: BucketNameSchema }, async ({ name }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -102,7 +102,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { 'Get details about a specific R2 bucket', { name: BucketNameSchema }, async ({ name }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -135,7 +135,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { 'Delete an R2 bucket', { name: BucketNameSchema }, async ({ name }) => { - const account_id = agent.getActiveAccountId() + const account_id = await agent.getActiveAccountId() if (!account_id) { return MISSING_ACCOUNT_ID_RESPONSE } @@ -172,7 +172,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // params: CorsGetParamsSchema.optional(), // }, // async ({ name, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -211,7 +211,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // cors_config: CorsRulesSchema, // }, // async ({ name, cors_config }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -250,7 +250,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // params: CorsDeleteParamsSchema.optional(), // }, // async ({ name, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -286,7 +286,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'List all of the domains for an R2 bucket', // { name: BucketNameSchema, params: CustomDomainListParamsSchema.optional() }, // async ({ name, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -323,7 +323,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // params: CustomDomainGetParamsSchema.optional(), // }, // async ({ name, domain, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -359,7 +359,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'Create a new domain for an R2 bucket', // { name: BucketNameSchema, params: CustomDomainCreateParamsSchema }, // async ({ name, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -399,7 +399,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // params: CustomDomainDeleteParamsSchema.optional(), // }, // async ({ name, domain, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -439,7 +439,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // params: CustomDomainUpdateParamsSchema, // }, // async ({ name, domain, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -475,7 +475,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'Get event notifications for an R2 bucket', // { name: BucketNameSchema, params: EventNotificationGetParamsSchema.optional() }, // async ({ name, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -515,7 +515,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // params: EventNotificationUpdateParamsSchema.optional(), // }, // async ({ name, queueId, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -555,7 +555,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // params: EventNotificationDeleteParamsSchema.optional(), // }, // async ({ name, queueId, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -591,7 +591,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'Get locks for an R2 bucket', // { name: BucketNameSchema, params: LockGetParamsSchema.optional() }, // async ({ name, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -624,7 +624,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'Update locks for an R2 bucket', // { name: BucketNameSchema, params: LockUpdateParamsSchema }, // async ({ name, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -657,7 +657,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'Create temporary credentials for an R2 bucket', // { params: TemporaryCredentialsCreateParamsSchema }, // async ({ params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -689,7 +689,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // ) // agent.server.tool('r2_metrics_list', 'List metrics for an R2 bucket', async () => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -721,7 +721,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'Get configuration for sippy for an R2 bucket', // { bucketName: BucketNameSchema, params: SippyGetParamsSchema.optional() }, // async ({ bucketName, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -755,7 +755,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'Update configuration for sippy for an R2 bucket', // { bucketName: BucketNameSchema, params: SippyUpdateParamsSchema }, // async ({ bucketName, params }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } @@ -788,7 +788,7 @@ export function registerR2BucketTools(agent: CloudflareMcpAgent) { // 'Delete sippy for an R2 bucket', // { bucketName: BucketNameSchema }, // async ({ bucketName }) => { - // const account_id = agent.getActiveAccountId() + // const account_id = await agent.getActiveAccountId() // if (!account_id) { // return MISSING_ACCOUNT_ID_RESPONSE // } diff --git a/packages/mcp-common/src/tools/worker.ts b/packages/mcp-common/src/tools/worker.ts index 132e6ded..0fbe62bd 100644 --- a/packages/mcp-common/src/tools/worker.ts +++ b/packages/mcp-common/src/tools/worker.ts @@ -16,7 +16,7 @@ const workerNameParam = z.string().describe('The name of the worker script to re export function registerWorkersTools(agent: CloudflareMcpAgent) { // Tool to list all workers agent.server.tool('workers_list', 'List all Workers in your Cloudflare account', async () => { - const accountId = agent.getActiveAccountId() + const accountId = await agent.getActiveAccountId() if (!accountId) { return { content: [ @@ -76,7 +76,7 @@ export function registerWorkersTools(agent: CloudflareMcpAgent) { 'Get the source code of a Cloudflare Worker', { scriptName: workerNameParam }, async (params) => { - const accountId = agent.getActiveAccountId() + const accountId = await agent.getActiveAccountId() if (!accountId) { return { content: [ diff --git a/packages/mcp-common/src/types/cloudflare-mcp-agent.ts b/packages/mcp-common/src/types/cloudflare-mcp-agent.ts index ffac6cf9..ca661e94 100644 --- a/packages/mcp-common/src/types/cloudflare-mcp-agent.ts +++ b/packages/mcp-common/src/types/cloudflare-mcp-agent.ts @@ -20,6 +20,6 @@ type McpAgentWithoutServer = Omit< export interface CloudflareMcpAgent extends McpAgentWithoutServer { server: CloudflareMCPServer - setActiveAccountId(accountId: string): void - getActiveAccountId(): string | null + setActiveAccountId(accountId: string): Promise + getActiveAccountId(): Promise }