Skip to content

Commit b047775

Browse files
Merge pull request #265 from guillermoscript/feature/mcp
fix(mcp): add dedicated API routes for RFC 9728 well-known metadata
2 parents 5daa53b + 8eff42d commit b047775

3 files changed

Lines changed: 73 additions & 13 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
3+
/**
4+
* RFC 9728 OAuth Authorization Server Metadata
5+
* Rewritten from /.well-known/oauth-authorization-server/api/mcp
6+
*/
7+
export async function GET(request: NextRequest) {
8+
const proto = request.headers.get('x-forwarded-proto') || 'https';
9+
const host = request.headers.get('host') || 'localhost:3000';
10+
const origin = `${proto}://${host}`;
11+
const mcpBase = `${origin}/api/mcp`;
12+
13+
return NextResponse.json({
14+
issuer: mcpBase,
15+
authorization_endpoint: `${mcpBase}/auth/authorize`,
16+
token_endpoint: `${mcpBase}/auth/token`,
17+
registration_endpoint: `${mcpBase}/auth/register`,
18+
response_types_supported: ['code'],
19+
grant_types_supported: ['authorization_code', 'refresh_token'],
20+
token_endpoint_auth_methods_supported: ['none', 'client_secret_post'],
21+
code_challenge_methods_supported: ['S256'],
22+
scopes_supported: ['mcp:tools'],
23+
revocation_endpoint: `${mcpBase}/auth/revoke`,
24+
}, {
25+
headers: {
26+
'cache-control': 'public, max-age=3600',
27+
'access-control-allow-origin': '*',
28+
},
29+
});
30+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
3+
/**
4+
* RFC 9728 OAuth Protected Resource Metadata
5+
* Rewritten from /.well-known/oauth-protected-resource/api/mcp
6+
*/
7+
export async function GET(request: NextRequest) {
8+
const proto = request.headers.get('x-forwarded-proto') || 'https';
9+
const host = request.headers.get('host') || 'localhost:3000';
10+
const origin = `${proto}://${host}`;
11+
const mcpBase = `${origin}/api/mcp`;
12+
13+
return NextResponse.json({
14+
resource: mcpBase,
15+
authorization_servers: [mcpBase],
16+
scopes_supported: ['mcp:tools'],
17+
bearer_methods_supported: ['header'],
18+
resource_name: 'LMS MCP Server',
19+
}, {
20+
headers: {
21+
'cache-control': 'public, max-age=3600',
22+
'access-control-allow-origin': '*',
23+
},
24+
});
25+
}

next.config.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,24 @@ const withNextIntl = createNextIntlPlugin('./i18n.ts');
66
const nextConfig: NextConfig = {
77
output: 'standalone',
88
async rewrites() {
9-
return [
10-
// RFC 9728: OAuth metadata at well-known paths for MCP
11-
// Claude Desktop fetches /.well-known/oauth-protected-resource/api/mcp
12-
// Rewrite to our catch-all proxy which serves tenant-aware metadata
13-
{
14-
source: '/.well-known/oauth-protected-resource/:path*',
15-
destination: '/api/mcp/.well-known/oauth-protected-resource',
16-
},
17-
{
18-
source: '/.well-known/oauth-authorization-server/:path*',
19-
destination: '/api/mcp/.well-known/oauth-authorization-server',
20-
},
21-
];
9+
return {
10+
// beforeFiles rewrites run before filesystem routes AND middleware
11+
beforeFiles: [
12+
// RFC 9728: OAuth metadata at well-known paths for MCP
13+
// Claude Desktop fetches /.well-known/oauth-protected-resource/api/mcp
14+
// Rewrite to API route that serves tenant-aware metadata
15+
{
16+
source: '/.well-known/oauth-protected-resource/:path*',
17+
destination: '/api/well-known/oauth-protected-resource',
18+
},
19+
{
20+
source: '/.well-known/oauth-authorization-server/:path*',
21+
destination: '/api/well-known/oauth-authorization-server',
22+
},
23+
],
24+
afterFiles: [],
25+
fallback: [],
26+
};
2227
},
2328
};
2429

0 commit comments

Comments
 (0)