# How to integrate Etermin MCP with Vercel AI SDK v6

```json
{
  "title": "How to integrate Etermin MCP with Vercel AI SDK v6",
  "toolkit": "Etermin",
  "toolkit_slug": "etermin",
  "framework": "Vercel AI SDK",
  "framework_slug": "ai-sdk",
  "url": "https://composio.dev/toolkits/etermin/framework/ai-sdk",
  "markdown_url": "https://composio.dev/toolkits/etermin/framework/ai-sdk.md",
  "updated_at": "2026-05-12T10:10:41.242Z"
}
```

## Introduction

This guide walks you through connecting Etermin to Vercel AI SDK v6 using the Composio tool router. By the end, you'll have a working Etermin agent that can add new client contact for booking, remove canceled appointment from calendar, create voucher for returning customer through natural language commands.
This guide will help you understand how to give your Vercel AI SDK agent real control over a Etermin account through Composio's Etermin MCP server.
Before we dive in, let's take a quick look at the key ideas and tools involved.

## Also integrate Etermin with

- [OpenAI Agents SDK](https://composio.dev/toolkits/etermin/framework/open-ai-agents-sdk)
- [Claude Agent SDK](https://composio.dev/toolkits/etermin/framework/claude-agents-sdk)
- [Claude Code](https://composio.dev/toolkits/etermin/framework/claude-code)
- [Claude Cowork](https://composio.dev/toolkits/etermin/framework/claude-cowork)
- [Codex](https://composio.dev/toolkits/etermin/framework/codex)
- [OpenClaw](https://composio.dev/toolkits/etermin/framework/openclaw)
- [Hermes](https://composio.dev/toolkits/etermin/framework/hermes-agent)
- [CLI](https://composio.dev/toolkits/etermin/framework/cli)
- [Google ADK](https://composio.dev/toolkits/etermin/framework/google-adk)
- [LangChain](https://composio.dev/toolkits/etermin/framework/langchain)
- [Mastra AI](https://composio.dev/toolkits/etermin/framework/mastra-ai)
- [LlamaIndex](https://composio.dev/toolkits/etermin/framework/llama-index)
- [CrewAI](https://composio.dev/toolkits/etermin/framework/crew-ai)

## TL;DR

Here's what you'll learn:
- How to set up and configure a Vercel AI SDK agent with Etermin integration
- Using Composio's Tool Router to dynamically load and access Etermin tools
- Creating an MCP client connection using HTTP transport
- Building an interactive CLI chat interface with conversation history management
- Handling tool calls and results within the Vercel AI SDK framework

## What is Vercel AI SDK?

The Vercel AI SDK is a TypeScript library for building AI-powered applications. It provides tools for creating agents that can use external services and maintain conversation state.
Key features include:
- streamText: Core function for streaming responses with real-time tool support
- MCP Client: Built-in support for Model Context Protocol via @ai-sdk/mcp
- Step Counting: Control multi-step tool execution with stopWhen: stepCountIs()
- OpenAI Provider: Native integration with OpenAI models

## What is the Etermin MCP server, and what's possible with it?

The Etermin MCP server is an implementation of the Model Context Protocol that connects your AI agent and assistants like Claude, Cursor, etc directly to your Etermin account. It provides structured and secure access to your appointment scheduling system, so your agent can perform actions like creating contacts, managing bookings, updating resources, and handling calendar events on your behalf.
- Automated contact and user creation: Instantly add new clients or team members to your Etermin account, streamlining onboarding and customer management.
- Effortless appointment and calendar management: Let your agent delete existing appointments or calendars, freeing up schedules and reducing manual work.
- Resource and service administration: Automatically create or remove resources and services, ensuring your booking system stays current as your business evolves.
- Voucher and webhook setup: Quickly generate new vouchers for promotions or set up webhooks for real-time event notifications and integrations.
- Contact and service deletion: Easily remove outdated contacts or services, keeping your scheduling platform organized and clutter-free.

## Supported Tools

| Tool slug | Name | Description |
|---|---|---|
| `ETERMIN_ASSIGN_CALENDAR_SERVICE` | Assign Calendar Service | Tool to assign a service to a calendar in eTermin. Use when you need to link a specific service to a calendar/employee resource, making the service available for that calendar. |
| `ETERMIN_CREATE_ABSENCE` | Create Absence | Tool to create an absence (non-working time) for a specific calendar. Use when you need to block time on a calendar for unavailability such as vacations, sick leave, or other non-working periods. |
| `ETERMIN_CREATE_ANCHORTIME` | Create Anchortime | Tool to create anchortimes (recurring time slots) in a calendar. Use when you need to define regular appointment availability. |
| `ETERMIN_CREATE_ANCHORTIME_BY_DATE` | Create Anchortime by Date | Tool to create anchortimes by date. Use when you need to block specific time slots on a calendar. Anchortimes define blocked periods for calendar scheduling where appointments cannot be booked. |
| `ETERMIN_CREATE_APPOINTMENT` | Create Appointment | Tool to create a new appointment in eTermin. Use when you need to schedule an appointment with specific start/end times and calendar. Requires at minimum the start time, end time, and calendar ID. Optionally accepts customer details, service information, pricing, and notification settings. |
| `ETERMIN_CREATE_APPOINTMENT_SYNC` | Create Appointment via Sync | Tool to create an appointment via sync in eTermin. Use when you need to synchronize an appointment from an external calendar system. Requires date/time in both local and UTC formats along with calendar ID, summary, and description. |
| `ETERMIN_CREATE_CALENDAR_RETURN_TIME` | Create Calendar Return Time | Tool to create a return time for a calendar. Use when scheduling recurring return times or availability windows for a specific weekday. Return times define when a calendar resource becomes available after being occupied. |
| `ETERMIN_CREATE_CONTACT` | Create Contact | Tool to create a new contact in eTermin. Use when you need to add a contact before scheduling appointments. |
| `ETERMIN_CREATE_SERVICE` | Create Service | Tool to create a new service in eTermin. Use when you need to add a service to a service group with specified duration and settings. |
| `ETERMIN_CREATE_SERVICE_GROUP` | Create Service Group | Tool to create a new service group in eTermin. Use when you need to organize services into groups for better booking page structure. Service groups help categorize services and control how they are displayed to customers during booking. |
| `ETERMIN_CREATE_USER` | Create User | Tool to create a new user. Use when you need to add users to eTermin after collecting their details. |
| `ETERMIN_CREATE_USERMAPPING` | Create Usermapping | Tool to create a new usermapping in eTermin. Use when you need to map phone numbers or other values to specific calendars and service groups. |
| `ETERMIN_CREATE_VOUCHER` | Create Voucher | Creates a new discount voucher in eTermin. Use this to set up promotional codes that customers can apply during booking. Supports both percentage and fixed amount discounts. |
| `ETERMIN_CREATE_WEBHOOK` | Create Webhook | Creates a webhook (web push notification) in eTermin to receive real-time updates about appointments. IMPORTANT: eTermin webhook configuration is typically managed through the web UI at API > API & Web Push. This action attempts API-based creation but will return a helpful message with UI instructions if the API endpoint is not available for your tenant. Webhooks can notify your application when appointments are created, modified, or deleted. Configure the webhook URL, optional authentication headers, and secret key for signature verification. |
| `ETERMIN_CREATE_WORKING_TIME` | Create Working Time | Tool to create a new working time slot in eTermin. Use when defining available time slots for appointments on a calendar. |
| `ETERMIN_CREATE_WORKING_TIMES_DATE` | Create Working Times Date | Tool to create a working times date slot for a calendar. Use when you need to define available time slots for appointments. |
| `ETERMIN_DELETE_ABSENCE` | Delete Absence | Tool to delete an absence (non-working time) from a calendar. Use when you need to remove a blocked time period from a calendar's availability. |
| `ETERMIN_DELETE_ANCHORTIME` | Delete Anchortime | Delete an anchortime from eTermin by its ID. Use this when you need to permanently remove an anchortime entry from the system. Note: This action is irreversible. |
| `ETERMIN_DELETE_ANCHORTIME_BY_DATE` | Delete Anchortime By Date | Delete an anchortime by date using its ID. Use when you need to remove a specific anchortime entry by date. Returns a success indicator along with any error messages if the deletion fails. |
| `ETERMIN_DELETE_APPOINTMENT` | Delete Appointment | Delete an existing appointment by its ID. Use the GET appointments action first to retrieve valid appointment IDs. Returns a success indicator along with any error messages if the deletion fails. |
| `ETERMIN_DELETE_APPOINTMENT_SYNC` | Delete Appointment via Sync | Tool to delete appointments via the sync endpoint. Use when you need to delete one or more appointments by ID or date range. Provide either an appointmentid for single deletion, or start/end dates for bulk deletion within a time range. |
| `ETERMIN_DELETE_CALENDAR` | Delete Calendar | Delete a calendar from your eTermin account. Use this tool to permanently remove a calendar by its ID. The calendar and all associated data will be deleted. This operation is idempotent - deleting a non-existent calendar will still return success. To find calendar IDs, first use ETERMIN_GET_CALENDARS to list all calendars. |
| `ETERMIN_DELETE_CALENDAR_RETURN_TIME` | Delete Calendar Return Time | Delete a return time from a calendar. Use when you need to remove a specific return time entry. |
| `ETERMIN_DELETE_CALENDAR_SERVICE` | Delete Calendar Service | Delete an assigned service from a calendar in eTermin. Use this action to remove a service assignment from a specific calendar by providing both the service assignment ID and the calendar ID. The deletion is permanent. |
| `ETERMIN_DELETE_CONTACT` | Delete Contact | Delete a contact from your eTermin account by its contact ID. Use this action when you need to permanently remove a contact from the system. The contact ID can be obtained using the Get Contacts action. Note: This action is irreversible. The contact will be permanently deleted. |
| `ETERMIN_DELETE_RESOURCE` | Delete Resource | Delete an eTermin resource by type and ID. Supports deleting contacts, services, users, calendars, vouchers, and working times. The resource ID can be obtained from listing or creating resources. |
| `ETERMIN_DELETE_SERVICE` | Delete Service | Permanently deletes a service from your eTermin account by its ID. Use this action to remove services that are no longer needed. The deletion is permanent and cannot be undone. Services with associated appointments may not be deletable. Before deleting, use the Get Services action to retrieve service IDs and verify which service you want to delete. |
| `ETERMIN_DELETE_SERVICEGROUP` | Delete Service Group | Delete a service group from your eTermin account by its ID. Use this action when you need to permanently remove a service group from the system. The deletion is permanent and cannot be undone. |
| `ETERMIN_DELETE_USER` | Delete User | Deletes an existing user from the eTermin account. Use the get_users action first to retrieve the user ID. The deletion is idempotent - deleting a non-existent user will not cause an error. |
| `ETERMIN_DELETE_USERMAPPING` | Delete Usermapping | Delete a usermapping by its ID. Use this action when you need to remove a usermapping from the eTermin system. |
| `ETERMIN_DELETE_VOUCHER` | Delete Voucher | Permanently deletes a voucher from eTermin by its voucher code. The operation is idempotent - deleting a non-existent voucher will still return success. Use the List Vouchers action first to get valid voucher codes if needed. |
| `ETERMIN_DELETE_WEBHOOK` | Delete Webhook | Delete an existing webhook by its unique identifier. Note: eTermin's webhook deletion endpoint is undocumented. This action attempts multiple candidate endpoints and returns a graceful message if webhook deletion is not supported via API for the tenant. In that case, users should manage webhooks through the eTermin web UI. |
| `ETERMIN_DELETE_WORKING_TIMES` | Delete Working Times | Tool to delete working times from a calendar. Use when removing time slots or clearing all working times from a calendar. If no specific working time ID is provided, all working slots for the calendar will be deleted. |
| `ETERMIN_DELETE_WORKING_TIMES_DATE` | Delete Working Times Date | Tool to delete working times date entries from eTermin. Use when removing working time slots by calendar or specific ID. Provide either calendarid to delete all working slots for a calendar, or id to delete a specific working time entry. |
| `ETERMIN_GET_ABSENCES` | Get Absences | Tool to retrieve absences (non-working times) for a specific calendar. Use when you need to check when a calendar is unavailable for appointments. |
| `ETERMIN_GET_ANCHORTIME_DATE` | Get Anchortime by Date | Tool to retrieve anchortimes by date. Use when you need to get existing anchortimes for calendars. Anchortimes define specific time slots or blocked periods for calendar scheduling. |
| `ETERMIN_GET_ANCHORTIMES` | Get Anchortimes | Tool to retrieve anchortime details. Use when you need to get anchortimes for calendars in your eTermin account. |
| `ETERMIN_GET_APPOINTMENT_SYNC` | Get Appointment Sync | Tool to synchronize appointments incrementally from eTermin. Use when you need to sync appointments using a sync token. For first sync, use synctoken=1. The API returns a new sync token in the response header for subsequent syncs. |
| `ETERMIN_GET_BOOKINGPAGE_LOGS` | Get Bookingpage Logs | Tool to retrieve bookingpage request logs from eTermin. Use when you need to analyze bookingpage access patterns and requests. |
| `ETERMIN_GET_CALENDAR_RETURN_TIME` | Get Calendar Return Time | Tool to retrieve return times for a specific calendar. Use when you need to get the configured return time periods for a calendar. |
| `ETERMIN_GET_CALENDARS` | Get Calendars | Tool to retrieve calendars. Use when listing all calendars in your eTermin account. |
| `ETERMIN_GET_CALENDARSERVICE` | Get Calendar Service Assignments | Tool to retrieve calendar service assignments. Use when you need to get services assigned to calendars in your eTermin account. |
| `ETERMIN_GET_COMPANY` | Get Company | Tool to retrieve company account details. Use when you need to get all company information from your eTermin account. |
| `ETERMIN_GET_CONTACT_BY_ID` | Get Contact By ID | Tool to retrieve a specific contact by ID, external ID, or email. Use when you need to get details of a single contact from eTermin. Provide at least one of: cid (internal ID), id (external UUID), or email. |
| `ETERMIN_GET_CONTACTS` | Get Contacts | Tool to retrieve a list of contacts. Use when you need to list all contacts in your eTermin account. |
| `ETERMIN_GET_DELETED_APPOINTMENTS` | Get Deleted Appointments | Tool to retrieve a list of deleted appointments from eTermin. Use when you need to track or audit deleted appointments, optionally filtered by deletion date range. Returns details including who deleted the appointment, when it was deleted, and the original appointment information. |
| `ETERMIN_GET_MESSAGE_LOGS` | Get Message Logs | Tool to retrieve message logs from eTermin. Use when you need to view emails and SMS that have been sent through the system. Returns details about sent messages including receiver, subject, date sent, and message type. |
| `ETERMIN_GET_RATING` | Get Customer Ratings | Tool to retrieve a list of customer ratings from eTermin. Use when you need to get feedback and ratings from customers for appointments. Returns rating details including customer feedback, rating score, and reply status. |
| `ETERMIN_GET_SERVICE_BY_ID` | Get Service By ID | Tool to retrieve a specific service from eTermin. Use when you need to get service details by service ID. |
| `ETERMIN_GET_SERVICE_CALENDAR` | Get Service Calendar | Tool to retrieve calendars for a specific service ID. Use when you need to find which calendars are associated with a particular service. |
| `ETERMIN_GET_SERVICEGROUP` | Get Service Group | Tool to retrieve service group details from eTermin. Use when you need to list service groups or get specific service group information by ID or language. |
| `ETERMIN_GET_SERVICES` | Get Services | Tool to retrieve a list of services. Use when you need to list available services in your eTermin account. |
| `ETERMIN_GET_SURVEY_RESULTS` | Get Survey Results | Tool to retrieve survey results from eTermin. Use when you need to get customer feedback and survey responses. Returns survey questions, answers, timestamps, and associated calendar/employee information. |
| `ETERMIN_GET_TIMESLOTS` | Get Timeslots | Tool to retrieve available timeslots for a specific calendar on a given date. Use when you need to check booking availability for a particular calendar. |
| `ETERMIN_GET_USERMAPPING` | Get Usermapping | Tool to retrieve usermapping information. Use when you need to get usermapping details or validate number search values. |
| `ETERMIN_GET_USERS` | Get Users | Tool to retrieve a list of users. Use when you need to list all users in your eTermin account. |
| `ETERMIN_GET_WORKING_TIMES` | Get Working Times | Tool to retrieve working times for a specific calendar. Use when confirming available time slots before booking appointments. |
| `ETERMIN_GET_WORKING_TIMES_DATE` | Get Working Times Date | Tool to retrieve working times for a specific calendar on a specific date. Use when checking available time slots for a particular date before booking appointments. |
| `ETERMIN_LIST_APPOINTMENTS` | List Appointments | Tool to retrieve a filtered list of appointments from eTermin in a specified date range. Use when you need to search for appointments by date range, calendar, customer, or other criteria. Returns appointment details including date/time, customer info, and service information. |
| `ETERMIN_LIST_VOUCHERS` | List Vouchers | Retrieve all vouchers (discount codes) from your eTermin account. Use this tool when you need to: - View all active and expired vouchers - Check voucher usage statistics (ContingentCounter vs ContingentMax) - Find voucher codes to share with customers - Monitor voucher validity periods Returns a list of vouchers with their discount values, validity dates, and usage restrictions. |
| `ETERMIN_LIST_WEBHOOKS` | List Webhooks | Tool to retrieve webhooks. Use when listing all webhooks in your eTermin account. |
| `ETERMIN_PUT_SERVICE` | Update Service via PUT | Tool to update a service in eTermin. Use when you need to modify service settings or configuration. |
| `ETERMIN_UPDATE_ABSENCE` | Update Absence | Tool to update an absence (non-working time) for a calendar in eTermin. Use when you need to modify an existing absence's dates, reason, or settings. |
| `ETERMIN_UPDATE_ANCHORTIME` | Update Anchortime | Update an existing anchortime in eTermin. Use this to modify anchortime settings such as start time, weekday, calendar assignment, or booking ignore behavior. The anchortime ID must be provided to identify which anchortime to update. |
| `ETERMIN_UPDATE_ANCHORTIME_BY_DATE` | Update Anchortime By Date | Tool to update anchortimes by date in eTermin. Use when you need to modify an existing anchortime's schedule. Anchortimes define recurring time slots for appointments on specific dates. |
| `ETERMIN_UPDATE_APPOINTMENT` | Update Appointment | Tool to update an existing appointment in eTermin. Use when you need to modify appointment details such as date/time, customer information, or service details. Only the appointment ID is required; provide only the fields you want to update. |
| `ETERMIN_UPDATE_CALENDAR` | Update Calendar | Update an existing calendar in eTermin. Use this tool to modify calendar settings such as name, description, capacity settings, and other configuration options. You must provide the calendar_id obtained from the get_calendars action. The eTermin API uses PUT /api/calendar with form-urlencoded data, where the calendar to update is specified by the 'id' parameter. |
| `ETERMIN_UPDATE_CALENDAR_RETURN_TIME` | Update Calendar Return Time | Tool to update a return time for a calendar in eTermin. Use when modifying existing return time settings such as start time, end time, weekday, or overnight settings. |
| `ETERMIN_UPDATE_CONTACT` | Update Contact | Tool to update an existing contact in eTermin. Use when you need to modify contact details by ID after confirming it exists. |
| `ETERMIN_UPDATE_RESOURCE` | Update Resource | Update an existing eTermin resource (contact, service, calendar, user, or voucher). The eTermin API requires PUT requests to the collection endpoint with form-urlencoded data including the resource ID in the body. ID field names by resource type: - contact: 'cid' - service: 'id' - calendar: 'id' - user: 'id' - voucher: 'id' |
| `ETERMIN_UPDATE_SERVICE` | Update Service | Tool to update an existing service. Use when you need to modify service details after confirming the service ID. |
| `ETERMIN_UPDATE_SERVICE_GROUP` | Update Service Group | Tool to update an existing service group in eTermin. Use when you need to modify service group properties such as name, display settings, or selection behavior. |
| `ETERMIN_UPDATE_SYNC_APPOINTMENT` | Update Synchronised Appointment | Tool to update a synchronised appointment in eTermin. Use when you need to modify an existing synced appointment with updated date/time, location, or other details. Requires the appointment ID (ExternalID) and updated date/time in both local and UTC formats. |
| `ETERMIN_UPDATE_USERMAPPING` | Update Usermapping | Update an existing usermapping in eTermin. Use this when you need to modify usermapping search criteria, calendar assignments, or service group mappings. |
| `ETERMIN_UPDATE_VOUCHER` | Update Voucher | Updates an existing voucher in eTermin. Use this to modify voucher properties such as description, discount amount, validity dates, or usage limits. The voucher must already exist - use ETERMIN_CREATE_VOUCHER to create new vouchers. |
| `ETERMIN_UPDATE_WEBHOOK` | Update Webhook | Update an existing webhook configuration in eTermin. Use this action to modify webhook settings such as the notification email, enable/disable web push notifications, or update the webhook endpoint URL. Note: eTermin webhook management is often only available through the web UI (Configuration -> Integration - API -> API tab). If the API does not support updates for your tenant, this action will return success=False with an informative message. Prerequisites: Use 'List Webhooks' to obtain a valid webhook_id. |
| `ETERMIN_UPDATE_WORKING_TIMES` | Update Working Times | Tool to update working times for a calendar in eTermin. Use when you need to modify existing working time slots, including their start/end times, weekdays, capacity limits, and other scheduling configurations. |
| `ETERMIN_UPDATE_WORKING_TIMES_DATE` | Update Working Times Date | Tool to update working times date for a calendar. Use when modifying existing working time slots for appointments. |

## Supported Triggers

None listed.

## Creating MCP Server - Stand-alone vs Composio SDK

The Etermin MCP server is an implementation of the Model Context Protocol that connects your AI agent to Etermin. It provides structured and secure access so your agent can perform Etermin operations on your behalf through a secure, permission-based interface.
With Composio's managed implementation, you don't have to create your own developer app. For production, if you're building an end product, we recommend using your own credentials. The managed server helps you prototype fast and go from 0-1 faster.

## Step-by-step Guide

### 1. Prerequisites

Before you begin, make sure you have:
- Node.js and npm installed
- A Composio account with API key
- An OpenAI API key

### 1. Getting API Keys for OpenAI and Composio

OpenAI API Key
- Go to the [OpenAI dashboard](https://platform.openai.com/settings/organization/api-keys) and create an API key. You'll need credits to use the models, or you can connect to another model provider.
- Keep the API key safe.
Composio API Key
- Log in to the [Composio dashboard](https://dashboard.composio.dev?utm_source=toolkits&utm_medium=framework_docs).
- Navigate to your API settings and generate a new API key.
- Store this key securely as you'll need it for authentication.

### 2. Install required dependencies

First, install the necessary packages for your project.
What you're installing:
- @ai-sdk/openai: Vercel AI SDK's OpenAI provider
- @ai-sdk/mcp: MCP client for Vercel AI SDK
- @composio/core: Composio SDK for tool integration
- ai: Core Vercel AI SDK
- dotenv: Environment variable management
```bash
npm install @ai-sdk/openai @ai-sdk/mcp @composio/core ai dotenv
```

### 3. Set up environment variables

Create a .env file in your project root.
What's needed:
- OPENAI_API_KEY: Your OpenAI API key for GPT model access
- COMPOSIO_API_KEY: Your Composio API key for tool access
- COMPOSIO_USER_ID: A unique identifier for the user session
```bash
OPENAI_API_KEY=your_openai_api_key_here
COMPOSIO_API_KEY=your_composio_api_key_here
COMPOSIO_USER_ID=your_user_id_here
```

### 4. Import required modules and validate environment

What's happening:
- We're importing all necessary libraries including Vercel AI SDK's OpenAI provider and Composio
- The dotenv/config import automatically loads environment variables
- The MCP client import enables connection to Composio's tool server
```typescript
import "dotenv/config";
import { openai } from "@ai-sdk/openai";
import { Composio } from "@composio/core";
import * as readline from "readline";
import { streamText, type ModelMessage, stepCountIs } from "ai";
import { createMCPClient } from "@ai-sdk/mcp";

const composioAPIKey = process.env.COMPOSIO_API_KEY;
const composioUserID = process.env.COMPOSIO_USER_ID;

if (!process.env.OPENAI_API_KEY) throw new Error("OPENAI_API_KEY is not set");
if (!composioAPIKey) throw new Error("COMPOSIO_API_KEY is not set");
if (!composioUserID) throw new Error("COMPOSIO_USER_ID is not set");

const composio = new Composio({
  apiKey: composioAPIKey,
});
```

### 5. Create Tool Router session and initialize MCP client

What's happening:
- We're creating a Tool Router session that gives your agent access to Etermin tools
- The create method takes the user ID and specifies which toolkits should be available
- The returned mcp object contains the URL and authentication headers needed to connect to the MCP server
- This session provides access to all Etermin-related tools through the MCP protocol
```typescript
async function main() {
  // Create a tool router session for the user
  const session = await composio.create(composioUserID!, {
    toolkits: ["etermin"],
  });

  const mcpUrl = session.mcp.url;
```

### 6. Connect to MCP server and retrieve tools

What's happening:
- We're creating an MCP client that connects to our Composio Tool Router session via HTTP
- The mcp.url provides the endpoint, and mcp.headers contains authentication credentials
- The type: "http" is important - Composio requires HTTP transport
- tools() retrieves all available Etermin tools that the agent can use
```typescript
const mcpClient = await createMCPClient({
  transport: {
    type: "http",
    url: mcpUrl,
    headers: session.mcp.headers, // Authentication headers for the Composio MCP server
  },
});

const tools = await mcpClient.tools();
```

### 7. Initialize conversation and CLI interface

What's happening:
- We initialize an empty messages array to maintain conversation history
- A readline interface is created to accept user input from the command line
- Instructions are displayed to guide the user on how to interact with the agent
```typescript
let messages: ModelMessage[] = [];

console.log("Chat started! Type 'exit' or 'quit' to end the conversation.\n");
console.log(
  "Ask any questions related to etermin, like summarize my last 5 emails, send an email, etc... :)))\n",
);

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  prompt: "> ",
});

rl.prompt();
```

### 8. Handle user input and stream responses with real-time tool feedback

What's happening:
- We use streamText instead of generateText to stream responses in real-time
- toolChoice: "auto" allows the model to decide when to use Etermin tools
- stopWhen: stepCountIs(10) allows up to 10 steps for complex multi-tool operations
- onStepFinish callback displays which tools are being used in real-time
- We iterate through the text stream to create a typewriter effect as the agent responds
- The complete response is added to conversation history to maintain context
- Errors are caught and displayed with helpful retry suggestions
```typescript
rl.on("line", async (userInput: string) => {
  const trimmedInput = userInput.trim();

  if (["exit", "quit", "bye"].includes(trimmedInput.toLowerCase())) {
    console.log("\nGoodbye!");
    rl.close();
    process.exit(0);
  }

  if (!trimmedInput) {
    rl.prompt();
    return;
  }

  messages.push({ role: "user", content: trimmedInput });
  console.log("\nAgent is thinking...\n");

  try {
    const stream = streamText({
      model: openai("gpt-5"),
      messages,
      tools,
      toolChoice: "auto",
      stopWhen: stepCountIs(10),
      onStepFinish: (step) => {
        for (const toolCall of step.toolCalls) {
          console.log(`[Using tool: ${toolCall.toolName}]`);
          }
          if (step.toolCalls.length > 0) {
            console.log(""); // Add space after tool calls
          }
        },
      });

      for await (const chunk of stream.textStream) {
        process.stdout.write(chunk);
      }

      console.log("\n\n---\n");

      // Get final result for message history
      const response = await stream.response;
      if (response?.messages?.length) {
        messages.push(...response.messages);
      }
    } catch (error) {
      console.error("\nAn error occurred while talking to the agent:");
      console.error(error);
      console.log(
        "\nYou can try again or restart the app if it keeps happening.\n",
      );
    } finally {
      rl.prompt();
    }
  });

  rl.on("close", async () => {
    await mcpClient.close();
    console.log("\n👋 Session ended.");
    process.exit(0);
  });
}

main().catch((err) => {
  console.error("Fatal error:", err);
  process.exit(1);
});
```

## Complete Code

```typescript
import "dotenv/config";
import { openai } from "@ai-sdk/openai";
import { Composio } from "@composio/core";
import * as readline from "readline";
import { streamText, type ModelMessage, stepCountIs } from "ai";
import { createMCPClient } from "@ai-sdk/mcp";

const composioAPIKey = process.env.COMPOSIO_API_KEY;
const composioUserID = process.env.COMPOSIO_USER_ID;

if (!process.env.OPENAI_API_KEY) throw new Error("OPENAI_API_KEY is not set");
if (!composioAPIKey) throw new Error("COMPOSIO_API_KEY is not set");
if (!composioUserID) throw new Error("COMPOSIO_USER_ID is not set");

const composio = new Composio({
  apiKey: composioAPIKey,
});

async function main() {
  // Create a tool router session for the user
  const session = await composio.create(composioUserID!, {
    toolkits: ["etermin"],
  });

  const mcpUrl = session.mcp.url;

  const mcpClient = await createMCPClient({
    transport: {
      type: "http",
      url: mcpUrl,
      headers: session.mcp.headers, // Authentication headers for the Composio MCP server
    },
  });

  const tools = await mcpClient.tools();

  let messages: ModelMessage[] = [];

  console.log("Chat started! Type 'exit' or 'quit' to end the conversation.\n");
  console.log(
    "Ask any questions related to etermin, like summarize my last 5 emails, send an email, etc... :)))\n",
  );

  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    prompt: "> ",
  });

  rl.prompt();

  rl.on("line", async (userInput: string) => {
    const trimmedInput = userInput.trim();

    if (["exit", "quit", "bye"].includes(trimmedInput.toLowerCase())) {
      console.log("\nGoodbye!");
      rl.close();
      process.exit(0);
    }

    if (!trimmedInput) {
      rl.prompt();
      return;
    }

    messages.push({ role: "user", content: trimmedInput });
    console.log("\nAgent is thinking...\n");

    try {
      const stream = streamText({
        model: openai("gpt-5"),
        messages,
        tools,
        toolChoice: "auto",
        stopWhen: stepCountIs(10),
        onStepFinish: (step) => {
          for (const toolCall of step.toolCalls) {
            console.log(`[Using tool: ${toolCall.toolName}]`);
          }
          if (step.toolCalls.length > 0) {
            console.log(""); // Add space after tool calls
          }
        },
      });

      for await (const chunk of stream.textStream) {
        process.stdout.write(chunk);
      }

      console.log("\n\n---\n");

      // Get final result for message history
      const response = await stream.response;
      if (response?.messages?.length) {
        messages.push(...response.messages);
      }
    } catch (error) {
      console.error("\nAn error occurred while talking to the agent:");
      console.error(error);
      console.log(
        "\nYou can try again or restart the app if it keeps happening.\n",
      );
    } finally {
      rl.prompt();
    }
  });

  rl.on("close", async () => {
    await mcpClient.close();
    console.log("\n👋 Session ended.");
    process.exit(0);
  });
}

main().catch((err) => {
  console.error("Fatal error:", err);
  process.exit(1);
});
```

## Conclusion

You've successfully built a Etermin agent using the Vercel AI SDK with streaming capabilities! This implementation provides a powerful foundation for building AI applications with natural language interfaces and real-time feedback.
Key features of this implementation:
- Real-time streaming responses for a better user experience with typewriter effect
- Live tool execution feedback showing which tools are being used as the agent works
- Dynamic tool loading through Composio's Tool Router with secure authentication
- Multi-step tool execution with configurable step limits (up to 10 steps)
- Comprehensive error handling for robust agent execution
- Conversation history maintenance for context-aware responses
You can extend this further by adding custom error handling, implementing specific business logic, or integrating additional Composio toolkits to create multi-app workflows.

## How to build Etermin MCP Agent with another framework

- [OpenAI Agents SDK](https://composio.dev/toolkits/etermin/framework/open-ai-agents-sdk)
- [Claude Agent SDK](https://composio.dev/toolkits/etermin/framework/claude-agents-sdk)
- [Claude Code](https://composio.dev/toolkits/etermin/framework/claude-code)
- [Claude Cowork](https://composio.dev/toolkits/etermin/framework/claude-cowork)
- [Codex](https://composio.dev/toolkits/etermin/framework/codex)
- [OpenClaw](https://composio.dev/toolkits/etermin/framework/openclaw)
- [Hermes](https://composio.dev/toolkits/etermin/framework/hermes-agent)
- [CLI](https://composio.dev/toolkits/etermin/framework/cli)
- [Google ADK](https://composio.dev/toolkits/etermin/framework/google-adk)
- [LangChain](https://composio.dev/toolkits/etermin/framework/langchain)
- [Mastra AI](https://composio.dev/toolkits/etermin/framework/mastra-ai)
- [LlamaIndex](https://composio.dev/toolkits/etermin/framework/llama-index)
- [CrewAI](https://composio.dev/toolkits/etermin/framework/crew-ai)

## Related Toolkits

- [Google Calendar](https://composio.dev/toolkits/googlecalendar) - Google Calendar is a time management service for scheduling meetings, events, and reminders. It streamlines personal and team organization with integrated notifications and sharing options.
- [Apaleo](https://composio.dev/toolkits/apaleo) - Apaleo is a cloud-based property management platform for hospitality businesses. It centralizes reservations, billing, and daily operations for smoother hotel management.
- [Appointo](https://composio.dev/toolkits/appointo) - Appointo is an appointment booking platform for Shopify stores. It lets businesses add online scheduling to their websites with zero coding.
- [Bart](https://composio.dev/toolkits/bart) - Bart is the Bay Area Rapid Transit system, providing fast public transportation across the San Francisco Bay Area. It helps commuters and travelers get real-time schedule info, plan routes, and stay updated on service changes.
- [Bookingmood](https://composio.dev/toolkits/bookingmood) - Bookingmood is commission-free booking software for rental businesses. It lets you manage reservations and sync bookings directly on your website.
- [Booqable](https://composio.dev/toolkits/booqable) - Booqable is a rental software platform for managing inventory, bookings, and reservations. It helps businesses streamline rentals and keep track of every item with ease.
- [Cal](https://composio.dev/toolkits/cal) - Cal is a meeting scheduling platform that offers shareable booking links and real-time calendar syncing. It streamlines the process of finding mutual availability to make scheduling effortless.
- [Calendarhero](https://composio.dev/toolkits/calendarhero) - Calendarhero is a powerful scheduling platform that streamlines your calendar management across multiple services. It helps you efficiently schedule, reschedule, and organize meetings without the back-and-forth.
- [Calendly](https://composio.dev/toolkits/calendly) - Calendly is an appointment scheduling tool that automates meeting invitations, availability checks, and reminders. It helps individuals and teams avoid endless email back-and-forth when booking meetings.
- [Evenium](https://composio.dev/toolkits/evenium) - Evenium is an all-in-one platform for managing professional events, from planning to analysis. It helps teams simplify event logistics, boost engagement, and track every detail in one place.
- [Eventee](https://composio.dev/toolkits/eventee) - Eventee is a user-friendly event management platform for mobile and web. It boosts attendee engagement for in-person, virtual, and hybrid events.
- [Eventzilla](https://composio.dev/toolkits/eventzilla) - Eventzilla is an event management platform for creating, promoting, and running events. It streamlines ticketing, registration, and attendee coordination for organizers.
- [Humanitix](https://composio.dev/toolkits/humanitix) - Humanitix is a not-for-profit ticketing platform that donates 100% of profits to charity. It empowers event organizers to make social impact with every ticket sold.
- [Lodgify](https://composio.dev/toolkits/lodgify) - Lodgify is an all-in-one vacation rental software for property managers and owners. It centralizes bookings, guest messaging, and channel synchronization in one dashboard.
- [Planyo Online Booking](https://composio.dev/toolkits/planyo_online_booking) - Planyo Online Booking is a flexible reservation system for managing bookings by day, hour, or event. It streamlines scheduling for any business needing reservations.
- [Scheduleonce](https://composio.dev/toolkits/scheduleonce) - Scheduleonce is a scheduling platform for capturing, qualifying, and engaging with inbound leads. It streamlines appointment booking and follow-ups for faster lead conversion.
- [Supersaas](https://composio.dev/toolkits/supersaas) - Supersaas is a flexible appointment scheduling platform for businesses and individuals. It streamlines bookings, reminders, and calendar management in one place.
- [Sympla](https://composio.dev/toolkits/sympla) - Sympla is a platform for managing in-person and online events, ticket sales, and registrations. It streamlines event setup, attendee tracking, and digital content delivery.
- [Gmail](https://composio.dev/toolkits/gmail) - Gmail is Google's email service with powerful spam protection, search, and G Suite integration. It keeps your inbox organized and makes communication fast and reliable.
- [Google Drive](https://composio.dev/toolkits/googledrive) - Google Drive is a cloud storage platform for uploading, sharing, and collaborating on files. It's perfect for keeping your documents accessible and organized across devices.

## Frequently Asked Questions

### What are the differences in Tool Router MCP and Etermin MCP?

With a standalone Etermin MCP server, the agents and LLMs can only access a fixed set of Etermin tools tied to that server. However, with the Composio Tool Router, agents can dynamically load tools from Etermin and many other apps based on the task at hand, all through a single MCP endpoint.

### Can I use Tool Router MCP with Vercel AI SDK v6?

Yes, you can. Vercel AI SDK v6 fully supports MCP integration. You get structured tool calling, message history handling, and model orchestration while Tool Router takes care of discovering and serving the right Etermin tools.

### Can I manage the permissions and scopes for Etermin while using Tool Router?

Yes, absolutely. You can configure which Etermin scopes and actions are allowed when connecting your account to Composio. You can also bring your own OAuth credentials or API configuration so you keep full control over what the agent can do.

### How safe is my data with Composio Tool Router?

All sensitive data such as tokens, keys, and configuration is fully encrypted at rest and in transit. Composio is SOC 2 Type 2 compliant and follows strict security practices so your Etermin data and credentials are handled as safely as possible.

---
[See all toolkits](https://composio.dev/toolkits) · [Composio docs](https://docs.composio.dev/llms.txt)
