MCP Server
MCP server overview: purpose, architecture, not deployed
MCP Server
The Model Context Protocol (MCP) server within the odys application serves as a crucial interface, exposing core business logic and data access as a set of well-defined tools. These tools are designed to be consumed by external AI models or other intelligent agents, allowing them to interact with and manage odys's operational data and functionalities programmatically. While the server is fully implemented, it is currently configured for local execution via standard I/O, rather than being deployed as a standalone service.
Overview
The odys-mcp-server is a dedicated component, residing in the mcp-server/ directory, built to adhere to the Model Context Protocol. Its primary purpose is to translate natural language requests from an AI model into structured calls to odys's internal functions, and then return the results in a format the AI can understand. This architecture enables intelligent automation and integration with AI-driven workflows for managing professionals, clients, and appointments.
The server leverages the @modelcontextprotocol/sdk to establish communication and handle requests. It defines a set of 4 distinct tools, each encapsulating a specific business operation: get_appointments_today, get_customer_by_phone, get_revenue_summary, and update_appointment_status. These tools are declared in mcp-server/src/tools.ts and exposed through the server's request handlers.
Communication with the MCP server is facilitated by a StdioServerTransport, as configured in mcp-server/src/server.ts. This means the server communicates over standard input/output streams, making it suitable for local development and integration with processes that can pipe data. The .mcp.json file explicitly defines how to run this server, specifying node ./mcp-server/dist/server.js as the command.
The odys application, at version 0.1.0, utilizes a robust Drizzle ORM for database interactions across its various tables, which include professionals, clients, appointments, and messages. The MCP server interacts directly with this database schema to fulfill tool requests.
Core Components
mcp-server/src/server.ts
This file acts as the entry point and orchestrator for the MCP server. It initializes a Server instance from the @modelcontextprotocol/sdk, identifying itself as "odys" with version "0.1.0" and declaring its tool capabilities.
The server sets up two primary request handlers:
ListToolsRequestSchema: When an MCP client requests a list of available tools, this handler responds by providing theTOOL_DEFINITIONSarray imported frommcp-server/src/tools.ts. This allows the AI model to dynamically discover the capabilities it can invoke.CallToolRequestSchema: This is the core handler for executing specific tools. It receives a request containing thenameof the tool to call and itsarguments. Aswitchstatement dispatches the request to the corresponding asynchronous function (e.g.,getAppointmentsToday,getCustomerByPhone) also imported frommcp-server/src/tools.ts. The results are then serialized into a JSON string and returned as content. Robust error handling is built into this handler, catching any exceptions during tool execution and returning a structured error message to the client, along with logging the error toconsole.error.
The main function in this file establishes the StdioServerTransport and connects the server, printing a confirmation message to console.error once it's running.
mcp-server/src/tools.ts
This file defines the actual business logic for each of the 4 MCP tools and their associated input schemas. It leverages zod for input validation and drizzle-orm for database operations. Each tool function also incorporates internal try/catch blocks, returning structured error objects (e.g., with an error field or success: false) upon failure in database operations or business logic.
GetAppointmentsTodayInput: Thiszodschema defines the expected input forget_appointments_today, requiring aprofessionalId(UUID string) and optionally atimezone(defaulting to "America/Sao_Paulo"). ThegetAppointmentsTodayfunction calculates the start and end times for "today" in the specified timezone using a customtzOffsetMsutility, then queries theappointments,clients, andprofessionalstables to retrieve relevant details.GetCustomerByPhoneInput: Forget_customer_by_phone, this schema expects aphonestring. ThegetCustomerByPhonefunction normalizes the input phone number usingnormalizeBrazilianPhoneand generatesgetPhoneVariantsto ensure comprehensive matching against theclientstable. It then fetches client details and their last 5 appointments from theappointmentstable.GetRevenueSummaryInput: This schema requires aprofessionalIdand aperiod(enum: "week", "month", "year"). ThegetRevenueSummaryfunction calculates a rolling time window based on theperiod. It retrieves thesessionPricefrom theprofessionalstable and then countsappointmentsfor that professional within the window wherepaymentStatusis 'captured'. It returns the total revenue, appointment count, and average ticket.UpdateAppointmentStatusInput: This schema defines the input forupdate_appointment_status, requiringappointmentId,professionalId, and astatus(fromAPPOINTMENT_STATUSES), with an optionalreason. TheupdateAppointmentStatusfunction first verifies that the appointment exists and belongs to the specifiedprofessionalIdto prevent unauthorized updates. It also checks if the status is already the target status, making the operation idempotent. If a change is needed, it updates thestatusand optionally thenotescolumn in theappointmentstable.
The TOOL_DEFINITIONS array provides the metadata for each tool, including its name, description, and inputSchema in a format consumable by the MCP SDK. This array is what the ListToolsRequestSchema handler returns.
Design Decisions
The design of the odys-mcp-server reflects several deliberate choices aimed at clarity, robustness, and maintainability:
- Clear Separation of Concerns: The architecture cleanly separates the Model Context Protocol handling (
mcp-server/src/server.ts) from the actual business logic and database interactions (mcp-server/src/tools.ts). This makes the server's role as a protocol adapter explicit and keeps the tool implementations focused on their specific tasks. - Strong Input Validation with Zod: Each tool's input is rigorously validated using
zodschemas (e.g.,GetAppointmentsTodayInput,GetCustomerByPhoneInput). This ensures that incoming requests conform to expected data types and formats, preventing common errors and improving the reliability of the tool calls. - Type-Safe Database Interactions with Drizzle ORM: The use of
drizzle-ormfor all database queries provides strong type safety, reducing the likelihood of runtime errors related to schema mismatches or incorrect query construction. This is evident in howschema.appointments,schema.clients, andschema.professionalsare used throughoutmcp-server/src/tools.ts. - Centralized Error Handling: The
CallToolRequestSchemahandler inmcp-server/src/server.tsincludes atry/catchblock that wraps all tool invocations. This provides a consistent mechanism for handling errors, logging them, and returning a structured error response to the MCP client, which is crucial for debugging and AI model feedback. - Explicit Tool Definitions: The
TOOL_DEFINITIONSarray inmcp-server/src/tools.tsserves as a self-documenting API for the MCP client. By providing aname,description, andinputSchemafor each tool, AI models can better understand how to use them without needing out-of-band information.
Potential Improvements
- Define Explicit Output Schemas for Tools: Currently, the
CallToolRequestSchemahandler inmcp-server/src/server.tsreturns tool results by simplyJSON.stringify(result, null, 2). While functional, this means the output structure is implicitly defined by the tool functions. Introducing explicitzodschemas for tool outputs, similar to how inputs are handled (e.g.,GetAppointmentsTodayOutput), would provide clearer contracts for AI models, enable better type-checking, and improve the overall robustness of the MCP interface. - Refine
getRevenueSummaryCalculation Logic: ThegetRevenueSummaryfunction inmcp-server/src/tools.tscalculatestotalRevenueCentsasappointmentCount * professional.sessionPrice. This assumes a fixedsessionPricefor all appointments within the period. IfsessionPricecan vary per appointment or if discounts are applied, this calculation might be inaccurate. A more robust approach would involve storing the actual price charged for each appointment in theappointmentstable and summing those values, rather than relying on the currentsessionPricefrom theprofessionalstable. - Enhance Timezone Handling: The
tzOffsetMsfunction inmcp-server/src/tools.tsis a custom implementation for calculating timezone offsets. While it works, timezone logic can be complex, especially with daylight saving time changes and historical data. Replacing this custom utility with a well-tested, dedicated library (e.g.,luxonordate-fns-tz) would likely improve accuracy, reduce potential bugs, and simplify maintenance for timezone-aware operations likegetAppointmentsToday.
References
mcp-server/src/server.tsmcp-server/src/tools.tsmcp-server/package.json.mcp.json