Skip to content

Feature: Add get_call_transcript Tool #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Changelog

## [Unreleased]
### Enhanced
- Improved message transformation in CallTranscriptOutput to handle optional properties
- Enhanced type safety for message handling
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ The Vapi MCP Server provides the following tools for integration:
- Immediate or scheduled calls
- Dynamic variable values through `assistantOverrides`
- `get_call`: Gets details of a specific call
- `get_call_transcript`: Gets the full transcript and conversation data of a specific call

> **Note:** The `create_call` action supports scheduling calls for immediate execution or for a future time. You can also pass dynamic variables using `assistantOverrides.variableValues` to personalize assistant messages.

Expand Down
15 changes: 15 additions & 0 deletions src/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,21 @@ export const GetCallInputSchema = z.object({
callId: z.string().describe('ID of the call to get'),
});

export const CallTranscriptOutputSchema = BaseResponseSchema.extend({
id: z.string(),
transcript: z.string().optional(),
messages: z.array(z.object({
role: z.string(),
message: z.string().optional(),
time: z.number().optional(),
duration: z.number().optional(),
})).optional(),
recordingUrl: z.string().optional(),
summary: z.string().optional(),
});

export const GetCallTranscriptInputSchema = GetCallInputSchema;

// ===== Phone Number Schemas =====

export const GetPhoneNumberInputSchema = z.object({
Expand Down
13 changes: 12 additions & 1 deletion src/tools/call.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { VapiClient, Vapi } from '@vapi-ai/server-sdk';

import { CallInputSchema, GetCallInputSchema } from '../schemas/index.js';
import { CallInputSchema, GetCallInputSchema, GetCallTranscriptInputSchema } from '../schemas/index.js';
import {
transformCallInput,
transformCallOutput,
transformCallTranscriptOutput,
} from '../transformers/index.js';
import { createToolHandler } from './utils.js';

Expand Down Expand Up @@ -42,4 +43,14 @@ export const registerCallTools = (
return transformCallOutput(call);
})
);

server.tool(
'get_call_transcript',
'Gets the full transcript and conversation data of a specific call',
GetCallTranscriptInputSchema.shape,
createToolHandler(async (data) => {
const call = await vapiClient.calls.get(data.callId);
return transformCallTranscriptOutput(call);
})
);
};
39 changes: 39 additions & 0 deletions src/transformers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CallInputSchema,
AssistantOutputSchema,
CallOutputSchema,
CallTranscriptOutputSchema,
PhoneNumberOutputSchema,
ToolOutputSchema,
UpdateAssistantInputSchema,
Expand Down Expand Up @@ -228,6 +229,44 @@ export function transformCallOutput(
};
}

export function transformCallTranscriptOutput(
call: Vapi.Call
): z.infer<typeof CallTranscriptOutputSchema> {
return {
id: call.id,
createdAt: call.createdAt,
updatedAt: call.updatedAt,
transcript: call.artifact?.transcript,
messages: call.artifact?.messages?.map(msg => {
// Handle different message types safely
const transformedMessage: any = {
role: msg.role,
time: msg.time || 0,
};

// Check if message has a 'message' property (UserMessage, BotMessage, SystemMessage, ToolCallMessage)
if ('message' in msg && typeof msg.message === 'string') {
transformedMessage.message = msg.message;
} else if ('result' in msg && typeof msg.result === 'string') {
// For ToolCallResultMessage, use result as message
transformedMessage.message = msg.result;
} else {
// Fallback for unknown message types - set to undefined since schema allows optional
transformedMessage.message = undefined;
}

// Check if message has a 'duration' property (UserMessage, BotMessage)
if ('duration' in msg && typeof msg.duration === 'number') {
transformedMessage.duration = msg.duration;
}

return transformedMessage;
}),
recordingUrl: call.artifact?.recordingUrl,
summary: call.analysis?.summary,
};
}

// ===== Phone Number Transformers =====

export function transformPhoneNumberOutput(
Expand Down