Skip to content

Conversation

@andrewdmontgomery
Copy link
Contributor

Summary

  • Implement OAuth 2.1 authentication flow with WordPress.com provider
  • Add comprehensive development environment configuration system
  • Extract tool registration into modular approach
  • Add new profile search capabilities and improved error handling

Key Changes

OAuth Authentication System:

  • Full OAuth 2.1 implementation using Cloudflare Workers OAuth Provider
  • WordPress.com integration with custom userinfo handling
  • PKCE (Proof Key for Code Exchange) for enhanced security
  • Consent screen and proper error handling
  • Session management with secure cookie handling

Development Environment:

  • New .dev.vars.example template with detailed setup instructions
  • Clear separation between secrets (.dev.vars) and configuration (wrangler.jsonc)
  • Comprehensive documentation for OAuth app setup

Tool System Improvements:

  • Modular tool registration architecture
  • New search-profiles-by-verified-account tool
  • Enhanced error handling and logging
  • Improved image utilities separation

Configuration Management:

  • Environment-specific configuration in wrangler.jsonc
  • Support for staging and production deployments
  • Enhanced security with proper secret management

Test Plan

  • Test OAuth flow locally with npm run dev
  • Verify consent screen and authentication process
  • Test profile search with verified accounts
  • Validate environment configuration setup
  • Test deployment to staging environment

🤖 Generated with Claude Code

…client

The fetch api client has a bug that causes it to fail to throw an error on non-2xx responses
@andrewdmontgomery andrewdmontgomery marked this pull request as draft July 30, 2025 16:48
Comment on lines +65 to +109
// Initialize the Hono app with routes for the OAuth Provider
const app = new Hono<{ Bindings: Env & { OAUTH_PROVIDER: any } }>();
app.get("/authorize", authorize);
app.post("/authorize/consent", confirmConsent);
app.get("/callback", callback);
app.post("/register", registerClient);

// Root endpoint for basic server info
app.get("/", (c) => {
const serverInfo = getServerInfo();
return c.json({
name: serverInfo.name,
version: serverInfo.version,
endpoints: {
mcp: "/mcp",
sse: "/sse",
oauth_authorize: "/authorize",
oauth_callback: "/callback",
oauth_token: "/token",
},
});
});

function createOAuthProviderIfConfigured(env: Env) {
// Only create OAuth provider if all required variables are set
if (!env.OAUTH_CLIENT_ID || !env.OAUTH_CLIENT_SECRET || !env.OAUTH_AUTHORIZATION_ENDPOINT) {
return null;
}

return new OAuthProvider({
apiHandlers: {
// @ts-ignore
"/mcp": GravatarMcpServer.serve("/mcp"),
// @ts-ignore
"/sse": GravatarMcpServer.serveSSE("/sse"),
},
// @ts-ignore
defaultHandler: app,
authorizeEndpoint: "/authorize",
tokenEndpoint: "/token",
tokenExchangeCallback: (options: any) => tokenExchangeCallback(options),
clientRegistrationEndpoint: "/register",
});
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main part of OAuth support. Most of the rest of the changes are there to support this.

Comment on lines +96 to +99
// @ts-ignore
"/mcp": GravatarMcpServer.serve("/mcp"),
// @ts-ignore
"/sse": GravatarMcpServer.serveSSE("/sse"),
Copy link
Contributor Author

@andrewdmontgomery andrewdmontgomery Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These // @ts-ignore are here because I couldn't figure out why TypeScript was complaining. Specifically, the error (which is hard to parse) says that the GravatarMcpServer.serve() function (and the other one) are returning a function signature that is slightly different from what the apiHandlers closure expects.

Yet this exact code checks out fine in Cloudflare's own production MCP servers:

return new OAuthProvider({
	apiHandlers: {
		'/mcp': DNSAnalyticsMCP.serve('/mcp'),
		'/sse': DNSAnalyticsMCP.serveSSE('/sse'),
	},
	// @ts-ignore
	defaultHandler: createAuthHandlers({ scopes: AnalyticsScopes, 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)
},

Note, however that the defaultHandler parameter has a similar problem in Cloudflare's servers, requiring the same comment.

Comment on lines +114 to +116
if (oauthProvider) {
return oauthProvider.fetch(request, env, ctx);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conditional logic probably isn't necessary, useful, or even desirable. If the proper OAuth settings aren't available, we should fix that problem rather than booting up a server that just doesn't support OAuth. Especially since many tools require it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants