Skip to main content
Glama
index.ts9.06 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ListToolsRequestSchema, CallToolRequestSchema, Tool, } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; import dotenv from 'dotenv'; import { UberClient } from './uber-client.js'; import { UberConfig } from './types.js'; // Load environment variables dotenv.config(); // Initialize Uber configuration const uberConfig: UberConfig = { clientId: process.env.UBER_CLIENT_ID || '', clientSecret: process.env.UBER_CLIENT_SECRET || '', serverToken: process.env.UBER_SERVER_TOKEN, redirectUri: process.env.UBER_REDIRECT_URI || 'http://localhost:3000/callback', apiBaseUrl: process.env.UBER_API_BASE_URL || 'https://api.uber.com', authBaseUrl: process.env.UBER_AUTH_BASE_URL || 'https://auth.uber.com', environment: (process.env.UBER_ENVIRONMENT as 'sandbox' | 'production') || 'sandbox', }; // Create Uber client const uberClient = new UberClient(uberConfig); // Store for user tokens (in production, use secure storage) const userTokens = new Map<string, string>(); // Define schemas for tool inputs const AuthorizeSchema = z.object({ userId: z.string().describe('Unique identifier for the user'), }); const SetTokenSchema = z.object({ userId: z.string().describe('Unique identifier for the user'), accessToken: z.string().describe('Uber access token for the user'), }); const PriceEstimateSchema = z.object({ userId: z.string().describe('Unique identifier for the user'), startLatitude: z.number().describe('Starting location latitude'), startLongitude: z.number().describe('Starting location longitude'), endLatitude: z.number().describe('Destination latitude'), endLongitude: z.number().describe('Destination longitude'), }); const RequestRideSchema = z.object({ userId: z.string().describe('Unique identifier for the user'), productId: z.string().describe('Uber product ID (from price estimates)'), startLatitude: z.number().describe('Starting location latitude'), startLongitude: z.number().describe('Starting location longitude'), endLatitude: z.number().describe('Destination latitude'), endLongitude: z.number().describe('Destination longitude'), fareId: z.string().optional().describe('Fare ID from price estimate'), }); const RideStatusSchema = z.object({ userId: z.string().describe('Unique identifier for the user'), requestId: z.string().describe('Ride request ID'), }); const CancelRideSchema = z.object({ userId: z.string().describe('Unique identifier for the user'), requestId: z.string().describe('Ride request ID to cancel'), }); // Convert Zod schemas to JSON Schema format const zodToJsonSchema = (schema: z.ZodObject<any>) => { const shape = schema.shape; const properties: Record<string, any> = {}; const required: string[] = []; for (const [key, value] of Object.entries(shape)) { const zodType = value as z.ZodTypeAny; const isOptional = zodType instanceof z.ZodOptional; const baseType = isOptional ? zodType.unwrap() : zodType; if (!isOptional) { required.push(key); } if (baseType instanceof z.ZodString) { properties[key] = { type: 'string' }; } else if (baseType instanceof z.ZodNumber) { properties[key] = { type: 'number' }; } // Add description if available if ((zodType as any)._def?.description) { properties[key].description = (zodType as any)._def.description; } } return { type: 'object' as const, properties, required, }; }; // Define available tools const TOOLS: Tool[] = [ { name: 'uber_get_auth_url', description: 'Get the Uber authorization URL for user to authenticate', inputSchema: zodToJsonSchema(AuthorizeSchema), }, { name: 'uber_set_access_token', description: 'Set the access token for a user after OAuth callback', inputSchema: zodToJsonSchema(SetTokenSchema), }, { name: 'uber_get_price_estimates', description: 'Get price estimates for a ride between two locations', inputSchema: zodToJsonSchema(PriceEstimateSchema), }, { name: 'uber_request_ride', description: 'Request an Uber ride', inputSchema: zodToJsonSchema(RequestRideSchema), }, { name: 'uber_get_ride_status', description: 'Get the current status of a ride request', inputSchema: zodToJsonSchema(RideStatusSchema), }, { name: 'uber_cancel_ride', description: 'Cancel an ongoing ride request', inputSchema: zodToJsonSchema(CancelRideSchema), }, ]; // Create MCP server const server = new Server( { name: 'mcp-uber', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Handle list tools request server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: TOOLS, }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'uber_get_auth_url': { const { userId } = AuthorizeSchema.parse(args); const authUrl = await uberClient.getAuthorizationUrl(userId); return { content: [ { type: 'text', text: `Please visit this URL to authorize Uber access: ${authUrl}`, }, ], }; } case 'uber_set_access_token': { const { userId, accessToken } = SetTokenSchema.parse(args); userTokens.set(userId, accessToken); uberClient.setAccessToken(accessToken); return { content: [ { type: 'text', text: 'Access token set successfully', }, ], }; } case 'uber_get_price_estimates': { const { userId, startLatitude, startLongitude, endLatitude, endLongitude } = PriceEstimateSchema.parse(args); const token = userTokens.get(userId); if (!token) { throw new Error('User not authenticated. Please authorize first.'); } uberClient.setAccessToken(token); const estimates = await uberClient.getPriceEstimates( startLatitude, startLongitude, endLatitude, endLongitude ); return { content: [ { type: 'text', text: JSON.stringify(estimates, null, 2), }, ], }; } case 'uber_request_ride': { const { userId, productId, startLatitude, startLongitude, endLatitude, endLongitude, fareId } = RequestRideSchema.parse(args); const token = userTokens.get(userId); if (!token) { throw new Error('User not authenticated. Please authorize first.'); } uberClient.setAccessToken(token); const rideRequest = await uberClient.requestRide( productId, startLatitude, startLongitude, endLatitude, endLongitude, fareId ); return { content: [ { type: 'text', text: JSON.stringify(rideRequest, null, 2), }, ], }; } case 'uber_get_ride_status': { const { userId, requestId } = RideStatusSchema.parse(args); const token = userTokens.get(userId); if (!token) { throw new Error('User not authenticated. Please authorize first.'); } uberClient.setAccessToken(token); const status = await uberClient.getRideStatus(requestId); return { content: [ { type: 'text', text: JSON.stringify(status, null, 2), }, ], }; } case 'uber_cancel_ride': { const { userId, requestId } = CancelRideSchema.parse(args); const token = userTokens.get(userId); if (!token) { throw new Error('User not authenticated. Please authorize first.'); } uberClient.setAccessToken(token); await uberClient.cancelRide(requestId); return { content: [ { type: 'text', text: 'Ride cancelled successfully', }, ], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], }; } }); // Start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('MCP Uber server started'); } main().catch((error) => { console.error('Server error:', error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/199-mcp/mcp-uber'

If you have feedback or need assistance with the MCP directory API, please join our Discord server