Skip to content
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
1 change: 1 addition & 0 deletions src/__tests__/mcp-server-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ describe('MCP Server E2E Test', () => {
expect(toolNames).toContain('list_calls');
expect(toolNames).toContain('create_call');
expect(toolNames).toContain('get_call');
expect(toolNames).toContain('get_call_details');
});

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

export const CALL_DETAIL_FIELDS = [
'transcript',
'recordingUrl',
'messages',
'costs',
'cost',
'analysis',
'summary',
'artifact',
] as const;

export const GetCallDetailsInputSchema = z.object({
callId: z.string().describe('ID of the call to get full details for'),
include: z
.array(z.enum(CALL_DETAIL_FIELDS))
.optional()
.describe(
'Subset of detail fields to return. Omit to return the full call object. Useful for keeping LLM context small on long calls.'
),
});

export const CallDetailsOutputSchema = CallOutputSchema.extend({
transcript: z.string().optional(),
recordingUrl: z.string().optional(),
summary: z.string().optional(),
messages: z.array(z.any()).optional(),
costs: z.array(z.any()).optional(),
cost: z.number().optional(),
analysis: z.any().optional(),
artifact: z.any().optional(),
});

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

export const GetPhoneNumberInputSchema = z.object({
Expand Down
17 changes: 16 additions & 1 deletion src/tools/call.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
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,
GetCallDetailsInputSchema,
} from '../schemas/index.js';
import {
transformCallInput,
transformCallOutput,
transformCallDetailsOutput,
} from '../transformers/index.js';
import { createToolHandler } from './utils.js';

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

server.tool(
'get_call_details',
'Gets full details of a specific call (transcript, recording URL, messages, costs, analysis, summary, artifact). Use after get_call when summary fields are not enough. Pass `include` to scope the response and avoid blowing past LLM context windows on long calls.',
GetCallDetailsInputSchema.shape,
createToolHandler(async (data) => {
const call = await vapiClient.calls.get(data.callId);
return transformCallDetailsOutput(call, data.include);
})
);
};
24 changes: 24 additions & 0 deletions src/transformers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
UpdateAssistantInputSchema,
CreateToolInputSchema,
UpdateToolInputSchema,
CALL_DETAIL_FIELDS,
} from '../schemas/index.js';

// ===== Assistant Transformers =====
Expand Down Expand Up @@ -228,6 +229,29 @@ export function transformCallOutput(
};
}

export function transformCallDetailsOutput(
call: Vapi.Call,
include?: ReadonlyArray<(typeof CALL_DETAIL_FIELDS)[number]>
): Record<string, unknown> {
const summary = transformCallOutput(call);
const callRecord = call as unknown as Record<string, unknown>;
const artifact = (callRecord.artifact ?? {}) as Record<string, unknown>;

const fields = include ?? CALL_DETAIL_FIELDS;
const details: Record<string, unknown> = {};
for (const field of fields) {
const value = callRecord[field] ?? artifact[field];
if (value !== undefined) {
details[field] = value;
}
}

if (include) {
return { id: call.id, ...details };
}
return { ...summary, ...details };
}

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

export function transformPhoneNumberOutput(
Expand Down
Loading