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
5 changes: 4 additions & 1 deletion apps/cloudflare-one-casb/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
CLOUDFLARE_CLIENT_ID=
CLOUDFLARE_CLIENT_SECRET=
CLOUDFLARE_CLIENT_SECRET=
DEV_DISABLE_OAUTH=
DEV_CLOUDFLARE_API_TOKEN=
DEV_CLOUDFLARE_EMAIL=
54 changes: 33 additions & 21 deletions apps/cloudflare-one-casb/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import OAuthProvider from '@cloudflare/workers-oauth-provider'
import { McpAgent } from 'agents/mcp'

import { createApiHandler } from '@repo/mcp-common/src/api-handler'
import {
createAuthHandlers,
handleTokenExchangeCallback,
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
import { handleDevMode } from '@repo/mcp-common/src/dev-mode'
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'
Expand All @@ -14,7 +16,7 @@ import { registerAccountTools } from '@repo/mcp-common/src/tools/account'
import { MetricsTracker } from '../../../packages/mcp-observability/src'
import { registerIntegrationsTools } from './tools/integrations'

import type { AccountSchema, UserSchema } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { AuthProps } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { Env } from './context'

export { UserDetails }
Expand All @@ -26,13 +28,11 @@ const metrics = new MetricsTracker(env.MCP_METRICS, {
version: env.MCP_SERVER_VERSION,
})

export type Props = {
accessToken: string
user: UserSchema['result']
accounts: AccountSchema['result']
}
// Context from the auth process, encrypted & stored in the auth token
// and provided to the DurableMCP as this.props
type Props = AuthProps

export type State = { activeAccountId: string | null }
type State = { activeAccountId: string | null }
export class CASBMCP extends McpAgent<Env, State, Props> {
_server: CloudflareMCPServer | undefined
set server(server: CloudflareMCPServer) {
Expand Down Expand Up @@ -92,17 +92,29 @@ const CloudflareOneCasbScopes = {
'teams:read': 'See Cloudflare One Resources',
} as const

export default new OAuthProvider({
apiRoute: '/sse',
// @ts-ignore
apiHandler: CASBMCP.mount('/sse'),
// @ts-ignore
defaultHandler: createAuthHandlers({ scopes: CloudflareOneCasbScopes, metrics }),
authorizeEndpoint: '/oauth/authorize',
tokenEndpoint: '/token',
tokenExchangeCallback: (options) =>
handleTokenExchangeCallback(options, env.CLOUDFLARE_CLIENT_ID, env.CLOUDFLARE_CLIENT_SECRET),
// Cloudflare access token TTL
accessTokenTTL: 3600,
clientRegistrationEndpoint: '/register',
})
export default {
fetch: async (req: Request, env: Env, ctx: ExecutionContext) => {
if (env.ENVIRONMENT === 'development' && env.DEV_DISABLE_OAUTH === 'true') {
return await handleDevMode(CASBMCP, req, env, ctx)
}

return new OAuthProvider({
apiRoute: ['/mcp', '/sse'],
// @ts-ignore
apiHandler: createApiHandler(CASBMCP),
// @ts-ignore
defaultHandler: createAuthHandlers({ scopes: CloudflareOneCasbScopes, metrics }),
authorizeEndpoint: '/oauth/authorize',
tokenEndpoint: '/token',
tokenExchangeCallback: (options) =>
handleTokenExchangeCallback(
options,
env.CLOUDFLARE_CLIENT_ID,
env.CLOUDFLARE_CLIENT_SECRET
),
// Cloudflare access token TTL
accessTokenTTL: 3600,
clientRegistrationEndpoint: '/register',
}).fetch(req, env, ctx)
},
}
5 changes: 5 additions & 0 deletions apps/dex-analysis/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CLOUDFLARE_CLIENT_ID=
CLOUDFLARE_CLIENT_SECRET=
DEV_DISABLE_OAUTH=
DEV_CLOUDFLARE_API_TOKEN=
DEV_CLOUDFLARE_EMAIL=
33 changes: 8 additions & 25 deletions apps/dex-analysis/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import OAuthProvider from '@cloudflare/workers-oauth-provider'
import { McpAgent } from 'agents/mcp'

import { createApiHandler } from '@repo/mcp-common/src/api-handler'
import {
createAuthHandlers,
getUserAndAccounts,
handleTokenExchangeCallback,
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
import { handleDevMode } from '@repo/mcp-common/src/dev-mode'
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'
Expand All @@ -15,7 +16,7 @@ import { MetricsTracker } from '@repo/mcp-observability'

import { registerDEXTools } from './tools/dex'

import type { AccountSchema, UserSchema } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { AuthProps } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { Env } from './context'

export { UserDetails }
Expand All @@ -29,13 +30,9 @@ const metrics = new MetricsTracker(env.MCP_METRICS, {

// Context from the auth process, encrypted & stored in the auth token
// and provided to the DurableMCP as this.props
export type Props = {
accessToken: string
user: UserSchema['result']
accounts: AccountSchema['result']
}
type Props = AuthProps

export type State = { activeAccountId: string | null }
type State = { activeAccountId: string | null }

export class CloudflareDEXMCP extends McpAgent<Env, State, Props> {
_server: CloudflareMCPServer | undefined
Expand Down Expand Up @@ -97,29 +94,15 @@ const DexScopes = {
'dex:read': 'See Cloudflare Cloudflare DEX data for your account',
} as const

// TODO: Move this in to mcp-common
async function handleDevMode(req: Request, env: Env, ctx: ExecutionContext) {
const { user, accounts } = await getUserAndAccounts(env.DEV_CLOUDFLARE_API_TOKEN, {
'X-Auth-Email': env.DEV_CLOUDFLARE_EMAIL,
'X-Auth-Key': env.DEV_CLOUDFLARE_API_TOKEN,
})
ctx.props = {
accessToken: env.DEV_CLOUDFLARE_API_TOKEN,
user,
accounts,
} as Props
return CloudflareDEXMCP.mount('/sse').fetch(req, env, ctx)
}

export default {
fetch: async (req: Request, env: Env, ctx: ExecutionContext) => {
if (env.ENVIRONMENT === 'development' && env.DEV_DISABLE_OAUTH === 'true') {
return await handleDevMode(req, env, ctx)
return await handleDevMode(CloudflareDEXMCP, req, env, ctx)
}

return new OAuthProvider({
apiRoute: '/sse',
apiHandler: CloudflareDEXMCP.mount('/sse'),
apiRoute: ['/mcp', '/sse'],
apiHandler: createApiHandler(CloudflareDEXMCP),
// @ts-ignore
defaultHandler: createAuthHandlers({ scopes: DexScopes, metrics }),
authorizeEndpoint: '/oauth/authorize',
Expand Down
32 changes: 8 additions & 24 deletions apps/radar/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import OAuthProvider from '@cloudflare/workers-oauth-provider'
import { McpAgent } from 'agents/mcp'

import { createApiHandler } from '@repo/mcp-common/src/api-handler'
import {
createAuthHandlers,
getUserAndAccounts,
handleTokenExchangeCallback,
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
import { handleDevMode } from '@repo/mcp-common/src/dev-mode'
import { getEnv } from '@repo/mcp-common/src/env'
import { RequiredScopes } from '@repo/mcp-common/src/scopes'
import { CloudflareMCPServer } from '@repo/mcp-common/src/server'
Expand All @@ -14,7 +15,7 @@ import { MetricsTracker } from '@repo/mcp-observability'
import { registerRadarTools } from './tools/radar'
import { registerUrlScannerTools } from './tools/url-scanner'

import type { UserSchema } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { AuthProps } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { Env } from './context'

const env = getEnv<Env>()
Expand All @@ -26,12 +27,9 @@ const metrics = new MetricsTracker(env.MCP_METRICS, {

// Context from the auth process, encrypted & stored in the auth token
// and provided to the DurableMCP as this.props
export type Props = {
accessToken: string
user: UserSchema['result']
}
type Props = AuthProps

export type State = never
type State = never

export class RadarMCP extends McpAgent<Env, State, Props> {
_server: CloudflareMCPServer | undefined
Expand Down Expand Up @@ -73,29 +71,15 @@ export class RadarMCP extends McpAgent<Env, State, Props> {
// Also remove URL_SCANNER_API_TOKEN env var
const RadarScopes = { ...RequiredScopes } as const

// TODO: Move this in to mcp-common
async function handleDevMode(req: Request, env: Env, ctx: ExecutionContext) {
const { user, accounts } = await getUserAndAccounts(env.DEV_CLOUDFLARE_API_TOKEN, {
'X-Auth-Email': env.DEV_CLOUDFLARE_EMAIL,
'X-Auth-Key': env.DEV_CLOUDFLARE_API_TOKEN,
})
ctx.props = {
accessToken: env.DEV_CLOUDFLARE_API_TOKEN,
user,
accounts,
} as Props
return RadarMCP.mount('/sse').fetch(req, env, ctx)
}

export default {
fetch: async (req: Request, env: Env, ctx: ExecutionContext) => {
if (env.ENVIRONMENT === 'development' && env.DEV_DISABLE_OAUTH === 'true') {
return await handleDevMode(req, env, ctx)
return await handleDevMode(RadarMCP, req, env, ctx)
}

return new OAuthProvider({
apiRoute: '/sse',
apiHandler: RadarMCP.mount('/sse'),
apiRoute: ['/mcp', '/sse'],
apiHandler: createApiHandler(RadarMCP),
// @ts-ignore
defaultHandler: createAuthHandlers({ scopes: RadarScopes, metrics }),
authorizeEndpoint: '/oauth/authorize',
Expand Down
31 changes: 7 additions & 24 deletions apps/sandbox-container/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import OAuthProvider from '@cloudflare/workers-oauth-provider'

import { createApiHandler } from '@repo/mcp-common/src/api-handler'
import {
createAuthHandlers,
getUserAndAccounts,
handleTokenExchangeCallback,
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
import { handleDevMode } from '@repo/mcp-common/src/dev-mode'
import { getEnv } from '@repo/mcp-common/src/env'
import { RequiredScopes } from '@repo/mcp-common/src/scopes'
import { MetricsTracker } from '@repo/mcp-observability'
Expand All @@ -13,7 +14,7 @@ import { ContainerManager } from './containerManager'
import { ContainerMcpAgent } from './containerMcp'

import type { McpAgent } from 'agents/mcp'
import type { AccountSchema, UserSchema } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { AuthProps } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { Env } from './context'

export { ContainerManager, ContainerMcpAgent }
Expand All @@ -27,11 +28,7 @@ const metrics = new MetricsTracker(env.MCP_METRICS, {

// Context from the auth process, encrypted & stored in the auth token
// and provided to the DurableMCP as this.props
export type Props = {
accessToken: string
user: UserSchema['result']
accounts: AccountSchema['result']
}
export type Props = AuthProps

const ContainerScopes = {
...RequiredScopes,
Expand All @@ -40,20 +37,6 @@ const ContainerScopes = {
'See and change Cloudflare Workers data such as zones, KV storage, namespaces, scripts, and routes.',
} as const

// TODO: Move this in to mcp-common
async function handleDevMode(req: Request, env: Env, ctx: ExecutionContext) {
const { user, accounts } = await getUserAndAccounts(env.DEV_CLOUDFLARE_API_TOKEN, {
'X-Auth-Email': env.DEV_CLOUDFLARE_EMAIL,
'X-Auth-Key': env.DEV_CLOUDFLARE_API_TOKEN,
})
ctx.props = {
accessToken: env.DEV_CLOUDFLARE_API_TOKEN,
user,
accounts,
} as Props
return ContainerMcpAgent.mount('/sse').fetch(req, env, ctx)
}

export default {
fetch: async (req: Request, env: Env, ctx: ExecutionContext) => {
// @ts-ignore
Expand All @@ -74,12 +57,12 @@ export default {
}

if (env.ENVIRONMENT === 'dev' && env.DEV_DISABLE_OAUTH === 'true') {
return await handleDevMode(req, env, ctx)
return await handleDevMode(ContainerMcpAgent, req, env, ctx)
}

return new OAuthProvider({
apiRoute: '/sse',
apiHandler: ContainerMcpAgent.mount('/sse', { binding: 'CONTAINER_MCP_AGENT' }),
apiRoute: ['/mcp', '/sse'],
apiHandler: createApiHandler(ContainerMcpAgent, { binding: 'CONTAINER_MCP_AGENT' }),
// @ts-ignore
defaultHandler: createAuthHandlers({ scopes: ContainerScopes, metrics }),
authorizeEndpoint: '/oauth/authorize',
Expand Down
13 changes: 5 additions & 8 deletions apps/workers-bindings/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import OAuthProvider from '@cloudflare/workers-oauth-provider'
import { McpAgent } from 'agents/mcp'

import { createApiHandler } from '@repo/mcp-common/src/api-handler'
import {
createAuthHandlers,
getUserAndAccounts,
Expand All @@ -17,7 +18,7 @@ import { registerR2BucketTools } from '@repo/mcp-common/src/tools/r2_bucket'
import { registerWorkersTools } from '@repo/mcp-common/src/tools/worker'
import { MetricsTracker } from '@repo/mcp-observability'

import type { AccountSchema, UserSchema } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { AuthProps } from '@repo/mcp-common/src/cloudflare-oauth-handler'
import type { Env } from './context'

export { UserDetails }
Expand All @@ -33,11 +34,7 @@ export type WorkersBindingsMCPState = { activeAccountId: string | null }

// Context from the auth process, encrypted & stored in the auth token
// and provided to the DurableMCP as this.props
export type Props = {
accessToken: string
user: UserSchema['result']
accounts: AccountSchema['result']
}
type Props = AuthProps

export class WorkersBindingsMCP extends McpAgent<Env, WorkersBindingsMCPState, Props> {
_server: CloudflareMCPServer | undefined
Expand Down Expand Up @@ -129,8 +126,8 @@ export default {
}

return new OAuthProvider({
apiRoute: '/sse',
apiHandler: WorkersBindingsMCP.mount('/sse'),
apiRoute: ['/mcp', '/sse'],
apiHandler: createApiHandler(WorkersBindingsMCP),
// @ts-ignore
defaultHandler: createAuthHandlers({ scopes: BindingsScopes, metrics }),
authorizeEndpoint: '/oauth/authorize',
Expand Down
5 changes: 5 additions & 0 deletions apps/workers-observability/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CLOUDFLARE_CLIENT_ID=
CLOUDFLARE_CLIENT_SECRET=
DEV_DISABLE_OAUTH=
DEV_CLOUDFLARE_API_TOKEN=
DEV_CLOUDFLARE_EMAIL=
Loading