Skip to content

Commit b77956f

Browse files
committed
Add dev mode auth to our mcp servers
1 parent 8360974 commit b77956f

File tree

14 files changed

+210
-75
lines changed

14 files changed

+210
-75
lines changed

apps/docs-autorag/.dev.vars.example

Whitespace-only changes.

apps/radar/.dev.vars.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
CLOUDFLARE_CLIENT_ID=
22
CLOUDFLARE_CLIENT_SECRET=
33
URL_SCANNER_API_TOKEN=
4+
DEV_DISABLE_OAUTH=
5+
DEV_CLOUDFLARE_API_TOKEN=
6+
DEV_CLOUDFLARE_EMAIL=

apps/radar/src/context.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ export interface Env {
1111
URL_SCANNER_API_TOKEN: string
1212
MCP_OBJECT: DurableObjectNamespace<RadarMCP>
1313
MCP_METRICS: AnalyticsEngineDataset
14+
DEV_DISABLE_OAUTH: string
15+
DEV_CLOUDFLARE_API_TOKEN: string
16+
DEV_CLOUDFLARE_EMAIL: string
1417
}

apps/radar/src/index.ts

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { McpAgent } from 'agents/mcp'
33

44
import {
55
createAuthHandlers,
6+
getUserAndAccounts,
67
handleTokenExchangeCallback,
78
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
89
import { getEnv } from '@repo/mcp-common/src/env'
@@ -74,16 +75,42 @@ const RadarScopes = {
7475
offline_access: 'Grants refresh tokens for long-lived access.',
7576
} as const
7677

77-
export default new OAuthProvider({
78-
apiRoute: '/sse',
79-
apiHandler: RadarMCP.mount('/sse'),
80-
// @ts-ignore
81-
defaultHandler: createAuthHandlers({ scopes: RadarScopes, metrics }),
82-
authorizeEndpoint: '/oauth/authorize',
83-
tokenEndpoint: '/token',
84-
tokenExchangeCallback: (options) =>
85-
handleTokenExchangeCallback(options, env.CLOUDFLARE_CLIENT_ID, env.CLOUDFLARE_CLIENT_SECRET),
86-
// Cloudflare access token TTL
87-
accessTokenTTL: 3600,
88-
clientRegistrationEndpoint: '/register',
89-
})
78+
// TODO: Move this in to wci-common
79+
async function handleDevMode(req: Request, env: Env, ctx: ExecutionContext) {
80+
const { user, accounts } = await getUserAndAccounts(env.DEV_CLOUDFLARE_API_TOKEN, {
81+
'X-Auth-Email': env.DEV_CLOUDFLARE_EMAIL,
82+
'X-Auth-Key': env.DEV_CLOUDFLARE_API_TOKEN,
83+
})
84+
ctx.props = {
85+
accessToken: env.DEV_CLOUDFLARE_API_TOKEN,
86+
user,
87+
accounts,
88+
} as Props
89+
return RadarMCP.mount('/sse').fetch(req, env, ctx)
90+
}
91+
92+
export default {
93+
fetch: async (req: Request, env: Env, ctx: ExecutionContext) => {
94+
if (env.ENVIRONMENT === 'development' && env.DEV_DISABLE_OAUTH === 'true') {
95+
return await handleDevMode(req, env, ctx)
96+
}
97+
98+
return new OAuthProvider({
99+
apiRoute: '/sse',
100+
apiHandler: RadarMCP.mount('/sse'),
101+
// @ts-ignore
102+
defaultHandler: createAuthHandlers({ scopes: RadarScopes, metrics }),
103+
authorizeEndpoint: '/oauth/authorize',
104+
tokenEndpoint: '/token',
105+
tokenExchangeCallback: (options) =>
106+
handleTokenExchangeCallback(
107+
options,
108+
env.CLOUDFLARE_CLIENT_ID,
109+
env.CLOUDFLARE_CLIENT_SECRET
110+
),
111+
// Cloudflare access token TTL
112+
accessTokenTTL: 3600,
113+
clientRegistrationEndpoint: '/register',
114+
}).fetch(req, env, ctx)
115+
},
116+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
CLOUDFLARE_CLIENT_ID=
2-
CLOUDFLARE_CLIENT_SECRET=
2+
CLOUDFLARE_CLIENT_SECRET=
3+
DEV_DISABLE_OAUTH=
4+
DEV_CLOUDFLARE_API_TOKEN=
5+
DEV_CLOUDFLARE_EMAIL=

apps/sandbox-container/server/context.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ export interface Env {
1212
CONTAINER_MANAGER: DurableObjectNamespace<ContainerManager>
1313
MCP_METRICS: AnalyticsEngineDataset
1414
AI: Ai
15+
DEV_DISABLE_OAUTH: string
16+
DEV_CLOUDFLARE_API_TOKEN: string
17+
DEV_CLOUDFLARE_EMAIL: string
1518
}

apps/sandbox-container/server/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import OAuthProvider from '@cloudflare/workers-oauth-provider'
22

33
import {
44
createAuthHandlers,
5+
getUserAndAccounts,
56
handleTokenExchangeCallback,
67
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
78
import { getEnv } from '@repo/mcp-common/src/env'
@@ -39,8 +40,22 @@ const ContainerScopes = {
3940
'See and change Cloudflare Workers data such as zones, KV storage, namespaces, scripts, and routes.',
4041
} as const
4142

43+
// TODO: Move this in to wci-common
44+
async function handleDevMode(req: Request, env: Env, ctx: ExecutionContext) {
45+
const { user, accounts } = await getUserAndAccounts(env.DEV_CLOUDFLARE_API_TOKEN, {
46+
'X-Auth-Email': env.DEV_CLOUDFLARE_EMAIL,
47+
'X-Auth-Key': env.DEV_CLOUDFLARE_API_TOKEN,
48+
})
49+
ctx.props = {
50+
accessToken: env.DEV_CLOUDFLARE_API_TOKEN,
51+
user,
52+
accounts,
53+
} as Props
54+
return ContainerMcpAgent.mount('/sse').fetch(req, env, ctx)
55+
}
56+
4257
export default {
43-
fetch: (req: Request, env: Env, ctx: ExecutionContext) => {
58+
fetch: async (req: Request, env: Env, ctx: ExecutionContext) => {
4459
// @ts-ignore
4560
if (env.ENVIRONMENT === 'test') {
4661
ctx.props = {
@@ -58,6 +73,10 @@ export default {
5873
)
5974
}
6075

76+
if (env.ENVIRONMENT === 'dev' && env.DEV_DISABLE_OAUTH === 'true') {
77+
return await handleDevMode(req, env, ctx)
78+
}
79+
6180
return new OAuthProvider({
6281
apiRoute: '/sse',
6382
apiHandler: ContainerMcpAgent.mount('/sse', { binding: 'CONTAINER_MCP_AGENT' }),
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
CLOUDFLARE_CLIENT_ID=
22
CLOUDFLARE_CLIENT_SECRET=
3+
DEV_DISABLE_OAUTH=
4+
DEV_CLOUDFLARE_API_TOKEN=
5+
DEV_CLOUDFLARE_EMAIL=

apps/workers-bindings/src/context.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ export interface Env {
99
CLOUDFLARE_CLIENT_SECRET: '<PLACEHOLDER>'
1010
MCP_OBJECT: DurableObjectNamespace<WorkersBindingsMCP>
1111
MCP_METRICS: AnalyticsEngineDataset
12+
DEV_DISABLE_OAUTH: string
13+
DEV_CLOUDFLARE_API_TOKEN: string
14+
DEV_CLOUDFLARE_EMAIL: string
1215
}

apps/workers-bindings/src/index.ts

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { McpAgent } from 'agents/mcp'
33

44
import {
55
createAuthHandlers,
6+
getUserAndAccounts,
67
handleTokenExchangeCallback,
78
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
89
import { getEnv } from '@repo/mcp-common/src/env'
@@ -103,17 +104,42 @@ const BindingsScopes = {
103104
'd1:write': 'Create, read, and write to D1 databases',
104105
} as const
105106

106-
// Export the OAuth handler as the default
107-
export default new OAuthProvider({
108-
apiRoute: '/sse',
109-
apiHandler: WorkersBindingsMCP.mount('/sse'),
110-
// @ts-ignore
111-
defaultHandler: createAuthHandlers({ scopes: BindingsScopes, metrics }),
112-
authorizeEndpoint: '/oauth/authorize',
113-
tokenEndpoint: '/token',
114-
tokenExchangeCallback: (options) =>
115-
handleTokenExchangeCallback(options, env.CLOUDFLARE_CLIENT_ID, env.CLOUDFLARE_CLIENT_SECRET),
116-
// Cloudflare access token TTL
117-
accessTokenTTL: 3600,
118-
clientRegistrationEndpoint: '/register',
119-
})
107+
// TODO: Move this in to wci-common
108+
async function handleDevMode(req: Request, env: Env, ctx: ExecutionContext) {
109+
const { user, accounts } = await getUserAndAccounts(env.DEV_CLOUDFLARE_API_TOKEN, {
110+
'X-Auth-Email': env.DEV_CLOUDFLARE_EMAIL,
111+
'X-Auth-Key': env.DEV_CLOUDFLARE_API_TOKEN,
112+
})
113+
ctx.props = {
114+
accessToken: env.DEV_CLOUDFLARE_API_TOKEN,
115+
user,
116+
accounts,
117+
} as Props
118+
return WorkersBindingsMCP.mount('/sse').fetch(req, env, ctx)
119+
}
120+
121+
export default {
122+
fetch: async (req: Request, env: Env, ctx: ExecutionContext) => {
123+
if (env.ENVIRONMENT === 'development' && env.DEV_DISABLE_OAUTH === 'true') {
124+
return await handleDevMode(req, env, ctx)
125+
}
126+
127+
return new OAuthProvider({
128+
apiRoute: '/sse',
129+
apiHandler: WorkersBindingsMCP.mount('/sse'),
130+
// @ts-ignore
131+
defaultHandler: createAuthHandlers({ scopes: BindingsScopes, metrics }),
132+
authorizeEndpoint: '/oauth/authorize',
133+
tokenEndpoint: '/token',
134+
tokenExchangeCallback: (options) =>
135+
handleTokenExchangeCallback(
136+
options,
137+
env.CLOUDFLARE_CLIENT_ID,
138+
env.CLOUDFLARE_CLIENT_SECRET
139+
),
140+
// Cloudflare access token TTL
141+
accessTokenTTL: 3600,
142+
clientRegistrationEndpoint: '/register',
143+
}).fetch(req, env, ctx)
144+
},
145+
}

0 commit comments

Comments
 (0)