Skip to content

Commit dad1aab

Browse files
RahulHereRahulHere
authored andcommitted
Format code
1 parent da1a30d commit dad1aab

26 files changed

Lines changed: 671 additions & 244 deletions

examples/auth/server.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Server settings
55
host=0.0.0.0
66
port=3001
7-
# server_url=https://marni-nightcapped-nonmeditatively.ngrok-free.dev
7+
server_url=https://marni-nightcapped-nonmeditatively.ngrok-free.dev
88

99
# OAuth/IDP settings
1010
# Uncomment and configure for Keycloak or other OAuth provider

examples/auth/src/index.ts

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,29 @@
77
* file for configuration (same format as the C++ auth example).
88
*/
99

10-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
10+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
1111
import {
1212
CallToolRequestSchema,
1313
ListToolsRequestSchema,
14-
} from "@modelcontextprotocol/sdk/types.js";
15-
import { GopherAuth } from "@gopher.security/gopher-mcp-js";
16-
import express, { Request, Response } from "express";
17-
import cors from "cors";
18-
import bodyParser from "body-parser";
19-
import path from "path";
20-
import { getWeather } from "./tools/get-weather.js";
21-
import { getForecast } from "./tools/get-forecast.js";
22-
import { getAlerts } from "./tools/get-alerts.js";
23-
import { MCPServer } from "./server.js";
14+
} from '@modelcontextprotocol/sdk/types.js';
15+
import { GopherAuth } from '@gopher.security/gopher-mcp-js';
16+
import express, { Request, Response } from 'express';
17+
import cors from 'cors';
18+
import bodyParser from 'body-parser';
19+
import path from 'path';
20+
import { getWeather } from './tools/get-weather.js';
21+
import { getForecast } from './tools/get-forecast.js';
22+
import { getAlerts } from './tools/get-alerts.js';
23+
import { MCPServer } from './server.js';
2424

2525
// Load config from server.config file
26-
const configPath = process.argv[2] || path.join(
27-
path.dirname(new URL(import.meta.url).pathname), '..', 'server.config'
28-
);
26+
const configPath =
27+
process.argv[2] ||
28+
path.join(
29+
path.dirname(new URL(import.meta.url).pathname),
30+
'..',
31+
'server.config'
32+
);
2933

3034
// Initialize GopherAuth from config file
3135
const auth = new GopherAuth({ configPath });
@@ -34,16 +38,19 @@ auth.initialize();
3438
// Read config values for server setup
3539
const SERVER_PORT = auth.nativeConfig?.getInt('port') ?? 3001;
3640
const SERVER_HOST = auth.nativeConfig?.getString('host') ?? '0.0.0.0';
37-
const SERVER_URL = auth.nativeConfig?.getString('server_url') ?? `http://localhost:${SERVER_PORT}`;
38-
const ALLOWED_SCOPES = auth.nativeConfig?.getString('allowed_scopes') ?? 'openid profile email';
41+
const SERVER_URL =
42+
auth.nativeConfig?.getString('server_url') ??
43+
`http://localhost:${SERVER_PORT}`;
44+
const ALLOWED_SCOPES =
45+
auth.nativeConfig?.getString('allowed_scopes') ?? 'openid profile email';
3946
const MCP_SCOPES = ALLOWED_SCOPES.split(' ').filter(Boolean);
4047

4148
// Factory: create a new MCP Server instance per session
4249
function createMcpServer(): Server {
4350
const server = new Server(
4451
{
45-
name: "js-auth-mcp-server",
46-
version: "1.0.0",
52+
name: 'js-auth-mcp-server',
53+
version: '1.0.0',
4754
},
4855
{
4956
capabilities: {
@@ -61,11 +68,11 @@ function createMcpServer(): Server {
6168
server.setRequestHandler(CallToolRequestSchema, async (request) => {
6269
const toolName = request.params.name;
6370
switch (toolName) {
64-
case "get-weather":
71+
case 'get-weather':
6572
return getWeather.handler(request);
66-
case "get-forecast":
73+
case 'get-forecast':
6774
return getForecast.handler(request);
68-
case "get-weather-alerts":
75+
case 'get-weather-alerts':
6976
return getAlerts.handler(request);
7077
default:
7178
throw new Error(`Unknown tool: ${toolName}`);
@@ -82,15 +89,17 @@ const mcpServer = new MCPServer(createMcpServer);
8289
async function startServer() {
8390
const app = express();
8491

85-
app.use(cors({
86-
exposedHeaders: ['mcp-session-id', 'Mcp-Session-Id'],
87-
}));
92+
app.use(
93+
cors({
94+
exposedHeaders: ['mcp-session-id', 'Mcp-Session-Id'],
95+
})
96+
);
8897
app.use(bodyParser.json());
8998

9099
// Health check
91-
app.get("/health", (_req: Request, res: Response) => {
100+
app.get('/health', (_req: Request, res: Response) => {
92101
res.json({
93-
status: "healthy",
102+
status: 'healthy',
94103
timestamp: new Date().toISOString(),
95104
activeSessions: mcpServer.getActiveSessions(),
96105
});
@@ -103,15 +112,15 @@ async function startServer() {
103112
});
104113

105114
// MCP endpoint with auth + StreamableHTTP
106-
const MCP_ENDPOINT = "/mcp";
115+
const MCP_ENDPOINT = '/mcp';
107116

108117
app.all(
109118
MCP_ENDPOINT,
110119
auth.expressMiddleware({
111120
publicMethods: ['initialize'],
112121
toolScopes: {
113-
"get-forecast": MCP_SCOPES,
114-
"get-weather-alerts": MCP_SCOPES,
122+
'get-forecast': MCP_SCOPES,
123+
'get-weather-alerts': MCP_SCOPES,
115124
},
116125
}),
117126
async (req: Request, res: Response) => {
@@ -120,26 +129,26 @@ async function startServer() {
120129
);
121130

122131
app.listen(SERVER_PORT, SERVER_HOST, () => {
123-
console.log("========================================");
124-
console.log(" JS Auth MCP Server");
125-
console.log("========================================");
132+
console.log('========================================');
133+
console.log(' JS Auth MCP Server');
134+
console.log('========================================');
126135
console.log(`🚀 Server: http://${SERVER_HOST}:${SERVER_PORT}`);
127136
console.log(`📡 MCP: ${SERVER_URL}${MCP_ENDPOINT}`);
128137
console.log(`🔐 OAuth: ${SERVER_URL}/.well-known/oauth-protected-resource`);
129138
console.log(`💚 Health: ${SERVER_URL}/health`);
130139
console.log(`📄 Config: ${configPath}`);
131140
console.log(`🔑 Auth: ${auth.isDisabled ? 'DISABLED' : 'ENABLED'}`);
132-
console.log("");
141+
console.log('');
133142
});
134143
}
135144

136-
process.on("SIGINT", () => {
137-
console.log("\nShutting down...");
145+
process.on('SIGINT', () => {
146+
console.log('\nShutting down...');
138147
auth.shutdown();
139148
process.exit(0);
140149
});
141150

142151
startServer().catch((error) => {
143-
console.error("Server error:", error);
152+
console.error('Server error:', error);
144153
process.exit(1);
145154
});

examples/auth/src/server.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ export class MCPServer {
2323

2424
constructor(serverFactory: ServerFactory) {
2525
this.serverFactory = serverFactory;
26-
console.log('🔒 MCP Server ready with StreamableHTTP transport (per-session mode)');
26+
console.log(
27+
'🔒 MCP Server ready with StreamableHTTP transport (per-session mode)'
28+
);
2729
}
2830

2931
/**
@@ -48,10 +50,15 @@ export class MCPServer {
4850
// Reuse existing transport for this session
4951
transport = this.transports.get(sessionId)!;
5052
console.log(`♻️ Reusing transport for session: ${sessionId}`);
51-
} else if (!sessionId && req.body?.method === 'notifications/initialized') {
53+
} else if (
54+
!sessionId &&
55+
req.body?.method === 'notifications/initialized'
56+
) {
5257
// MCP Inspector sends notifications/initialized without session ID.
5358
// This is a fire-and-forget notification — acknowledge and return.
54-
console.log(`📝 Accepting notifications/initialized without session ID`);
59+
console.log(
60+
`📝 Accepting notifications/initialized without session ID`
61+
);
5562
res.status(202).end();
5663
return;
5764
} else if (!sessionId && isInitializeRequest(req.body)) {
@@ -64,14 +71,16 @@ export class MCPServer {
6471
// Store the transport by session ID when session is initialized
6572
console.log(`✅ Session initialized with ID: ${newSessionId}`);
6673
this.transports.set(newSessionId, transport);
67-
}
74+
},
6875
});
6976

7077
// Set up onclose handler to clean up transport when closed
7178
transport.onclose = () => {
7279
const sid = transport.sessionId;
7380
if (sid && this.transports.has(sid)) {
74-
console.log(`🗑️ Transport closed for session ${sid}, removing from map`);
81+
console.log(
82+
`🗑️ Transport closed for session ${sid}, removing from map`
83+
);
7584
this.transports.delete(sid);
7685
}
7786
};
@@ -85,20 +94,25 @@ export class MCPServer {
8594
console.log(`📡 GET request without session — may be SSE probe`);
8695
res.status(405).json({
8796
jsonrpc: '2.0',
88-
error: { code: -32000, message: 'Method not allowed. Initialize first with POST.' },
97+
error: {
98+
code: -32000,
99+
message: 'Method not allowed. Initialize first with POST.',
100+
},
89101
id: null,
90102
});
91103
return;
92104
} else {
93105
// Invalid request - no session ID or not initialization request
94-
console.error(`❌ Invalid request: sessionId=${sessionId}, method=${method}, body.method=${req.body?.method}`);
106+
console.error(
107+
`❌ Invalid request: sessionId=${sessionId}, method=${method}, body.method=${req.body?.method}`
108+
);
95109
res.status(400).json({
96110
jsonrpc: '2.0',
97111
error: {
98112
code: -32000,
99-
message: 'Bad Request: No valid session ID provided'
113+
message: 'Bad Request: No valid session ID provided',
100114
},
101-
id: null
115+
id: null,
102116
});
103117
return;
104118
}
@@ -111,7 +125,6 @@ export class MCPServer {
111125
console.log(`📝 Storing transport for session: ${transport.sessionId}`);
112126
this.transports.set(transport.sessionId, transport);
113127
}
114-
115128
} catch (error: any) {
116129
console.error('❌ Error handling request:', error.message);
117130

examples/auth/src/tools/admin-tool.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ export const adminToolHandler = async (request: any) => {
4545
},
4646
};
4747

48-
const result = actionResults[action as keyof typeof actionResults] || { error: 'Unknown action' };
48+
const result = actionResults[action as keyof typeof actionResults] || {
49+
error: 'Unknown action',
50+
};
4951

5052
return {
5153
content: [

examples/auth/src/tools/get-alerts.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
*/
55
export const getAlerts = {
66
name: 'get-weather-alerts',
7-
description: 'Get weather alerts and warnings for a region (requires mcp:admin scope)',
7+
description:
8+
'Get weather alerts and warnings for a region (requires mcp:admin scope)',
89
inputSchema: {
910
type: 'object',
1011
properties: {
@@ -20,8 +21,16 @@ export const getAlerts = {
2021

2122
// Simulate weather alerts
2223
const alerts = [
23-
{ severity: 'moderate', type: 'Heavy Rain', message: 'Heavy rain expected in the next 6 hours' },
24-
{ severity: 'low', type: 'Wind', message: 'Strong winds possible this evening' },
24+
{
25+
severity: 'moderate',
26+
type: 'Heavy Rain',
27+
message: 'Heavy rain expected in the next 6 hours',
28+
},
29+
{
30+
severity: 'low',
31+
type: 'Wind',
32+
message: 'Strong winds possible this evening',
33+
},
2534
];
2635

2736
const hasAlerts = Math.random() > 0.5;
@@ -38,7 +47,10 @@ export const getAlerts = {
3847
}
3948

4049
const alertText = alerts
41-
.map((alert) => `[${alert.severity.toUpperCase()}] ${alert.type}: ${alert.message}`)
50+
.map(
51+
(alert) =>
52+
`[${alert.severity.toUpperCase()}] ${alert.type}: ${alert.message}`
53+
)
4254
.join('\n');
4355

4456
return {

examples/auth/src/tools/get-forecast.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
*/
55
export const getForecast = {
66
name: 'get-forecast',
7-
description: 'Get 5-day weather forecast for a city (requires authentication with mcp:read scope)',
7+
description:
8+
'Get 5-day weather forecast for a city (requires authentication with mcp:read scope)',
89
inputSchema: {
910
type: 'object',
1011
properties: {
@@ -37,12 +38,17 @@ export const getForecast = {
3738
date: date.toLocaleDateString(),
3839
temp_high: Math.floor(Math.random() * 10) + 20,
3940
temp_low: Math.floor(Math.random() * 10) + 10,
40-
condition: ['Sunny', 'Cloudy', 'Rainy', 'Partly Cloudy'][Math.floor(Math.random() * 4)],
41+
condition: ['Sunny', 'Cloudy', 'Rainy', 'Partly Cloudy'][
42+
Math.floor(Math.random() * 4)
43+
],
4144
});
4245
}
4346

4447
const forecastText = forecast
45-
.map((day) => `${day.date}: ${day.temp_low}-${day.temp_high}°C, ${day.condition}`)
48+
.map(
49+
(day) =>
50+
`${day.date}: ${day.temp_low}-${day.temp_high}°C, ${day.condition}`
51+
)
4652
.join('\n');
4753

4854
return {

examples/auth/src/tools/get-weather.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,18 @@ export const getWeather = {
2020

2121
// Simulate weather data (in a real app, you'd call a weather API)
2222
const weatherData = {
23-
'London': { temp: 15, condition: 'Cloudy', humidity: 75 },
23+
London: { temp: 15, condition: 'Cloudy', humidity: 75 },
2424
'New York': { temp: 22, condition: 'Sunny', humidity: 60 },
25-
'Tokyo': { temp: 18, condition: 'Rainy', humidity: 80 },
26-
'Paris': { temp: 17, condition: 'Partly Cloudy', humidity: 70 },
27-
'Sydney': { temp: 25, condition: 'Sunny', humidity: 55 },
25+
Tokyo: { temp: 18, condition: 'Rainy', humidity: 80 },
26+
Paris: { temp: 17, condition: 'Partly Cloudy', humidity: 70 },
27+
Sydney: { temp: 25, condition: 'Sunny', humidity: 55 },
2828
};
2929

3030
const weather = weatherData[city as keyof typeof weatherData] || {
3131
temp: Math.floor(Math.random() * 30) + 10,
32-
condition: ['Sunny', 'Cloudy', 'Rainy', 'Partly Cloudy'][Math.floor(Math.random() * 4)],
32+
condition: ['Sunny', 'Cloudy', 'Rainy', 'Partly Cloudy'][
33+
Math.floor(Math.random() * 4)
34+
],
3335
humidity: Math.floor(Math.random() * 40) + 50,
3436
};
3537

examples/auth/src/tools/protected-tool.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ export const protectedToolHandler = async (request: any) => {
4646
},
4747
};
4848

49-
const data = mockData[dataType as keyof typeof mockData] || { error: 'Unknown data type' };
49+
const data = mockData[dataType as keyof typeof mockData] || {
50+
error: 'Unknown data type',
51+
};
5052

5153
return {
5254
content: [

examples/auth/src/tools/user-context-tool.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
export const userContextTool = {
77
name: 'user-profile',
8-
description: 'Get personalized profile information using authentication context',
8+
description:
9+
'Get personalized profile information using authentication context',
910
inputSchema: {
1011
type: 'object',
1112
properties: {},
@@ -30,7 +31,9 @@ export const userContextToolHandler = async (request: any) => {
3031
const issuedAt = new Date(iat * 1000);
3132
const expiresAt = new Date(exp * 1000);
3233
const now = new Date();
33-
const timeRemaining = Math.floor((expiresAt.getTime() - now.getTime()) / 1000 / 60); // minutes
34+
const timeRemaining = Math.floor(
35+
(expiresAt.getTime() - now.getTime()) / 1000 / 60
36+
); // minutes
3437

3538
return {
3639
content: [

0 commit comments

Comments
 (0)