// =============================================================================
// MCP SERVER SETUP
// =============================================================================
// Same structure as basic MCP server.
// The difference is tools use A2A (for food) and AP2 (for payments).
// =============================================================================
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import type {
PlaceOrderArgs,
ProcessPaymentArgs,
ProcessRefundArgs,
PaymentStatusParams,
} from './interfaces.js';
import {
searchRestaurantsTool,
getMenuTool,
searchMenuItemsTool,
checkDeliveryEstimateTool,
placeOrderTool,
checkOrderStatusTool,
handleSearchRestaurants,
handleGetMenu,
handleSearchMenuItems,
handleCheckDeliveryEstimate,
handlePlaceOrder,
handleCheckOrderStatus,
} from './tools.js';
import {
processPaymentTool,
checkPaymentStatusTool,
processRefundTool,
handleProcessPayment,
handleCheckPaymentStatus,
handleProcessRefund,
} from './ap2-tools.js';
import {
userPreferencesResource,
userLocationResource,
userOrderHistoryResource,
readUserPreferences,
readUserLocation,
readOrderHistory,
} from './resources.js';
export async function createServer(): Promise<McpServer> {
const mcpServer = new McpServer(
{ name: 'mcp-a2a-ap2-imhungry', version: '1.0.0' },
{ capabilities: { tools: {}, resources: {} } }
);
const server = mcpServer.server;
// List tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
searchRestaurantsTool,
getMenuTool,
searchMenuItemsTool,
checkDeliveryEstimateTool,
placeOrderTool,
checkOrderStatusTool,
processPaymentTool,
checkPaymentStatusTool,
processRefundTool,
],
}));
// List resources
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
userPreferencesResource,
userLocationResource,
userOrderHistoryResource,
],
}));
// Read resource
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
let text = '';
switch (uri) {
case 'user://preferences':
text = await readUserPreferences();
break;
case 'user://location':
text = await readUserLocation();
break;
case 'user://order-history':
text = await readOrderHistory();
break;
default:
throw new Error(`Unknown resource: ${uri}`);
}
return { contents: [{ uri, mimeType: 'application/json', text }] };
});
// Call tool
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
let result: unknown;
switch (name) {
// A2A tools
case 'search_restaurants':
result = await handleSearchRestaurants(args as { query: string });
break;
case 'get_menu':
result = await handleGetMenu(args as { restaurantId: string });
break;
case 'search_menu_items':
result = await handleSearchMenuItems(args as { query: string; limit?: number });
break;
case 'check_delivery_estimate':
result = await handleCheckDeliveryEstimate(args as { restaurantId: string });
break;
case 'place_order':
result = await handlePlaceOrder(args as unknown as PlaceOrderArgs);
break;
case 'check_order_status':
result = await handleCheckOrderStatus(args as { orderId: string });
break;
// AP2 tools
case 'process_payment':
result = await handleProcessPayment(args as unknown as ProcessPaymentArgs);
break;
case 'check_payment_status':
result = await handleCheckPaymentStatus(args as unknown as PaymentStatusParams);
break;
case 'process_refund':
result = await handleProcessRefund(args as unknown as ProcessRefundArgs);
break;
default:
throw new Error(`Unknown tool: ${name}`);
}
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
});
return mcpServer;
}