Skip to content
Merged
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
2 changes: 1 addition & 1 deletion apps/sim/lib/sim-search/live/fireflies-mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export async function searchFirefliesMcp(
const data = toRecord(result)
const rows = Array.isArray(result)
? result
: (data.transcripts ?? toRecord(data.data).transcripts)
: (data.transcripts ?? (Array.isArray(data.data) ? data.data : toRecord(data.data).transcripts))
if (!Array.isArray(rows)) {
logger.warn('Unsupported Fireflies transcript list response shape', {
response: responseShape(result),
Expand Down
101 changes: 79 additions & 22 deletions apps/sim/lib/sim-search/live/meeting-mcp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,81 @@ const meetingId = '11111111-2222-4333-8444-555555555555'
* an unrelated read response is attached to a signed reference; malformed wire shapes hide gaps.
*/
describe('meeting MCP provider wire contracts', () => {
it('finds spoken Fireflies content and continues a full metadata page without inventing modification times', async () => {
const client: ManagedSearchMcpClient = {
async call(name, args) {
if (name !== 'fireflies_get_transcripts' || args.scope !== 'all' || args.format !== 'json')
throw new Error('Transcript-content search requires all scope and JSON output')
if (args.skip !== 10) throw new Error('Wrong continuation offset')
return {
transcripts: [
it.each(['bare array', 'data array', 'transcripts', 'nested transcripts'] as const)(
'finds spoken Fireflies content and continues a %s page without inventing modification times',
async (shape) => {
const client: ManagedSearchMcpClient = {
async call(name, args) {
if (
name !== 'fireflies_get_transcripts' ||
args.scope !== 'all' ||
args.format !== 'json'
)
throw new Error('Transcript-content search requires all scope and JSON output')
if (args.skip !== 10) throw new Error('Wrong continuation offset')
const transcripts = [
{
id: 'meeting-1',
title: 'Planning',
date: 1788220800000,
summary: { overview: 'Launch in September' },
},
{ id: 'meeting-2', title: 'Next match' },
]
if (shape === 'bare array') return transcripts
if (shape === 'data array') return { data: transcripts }
if (shape === 'nested transcripts') return { data: { transcripts } }
return { transcripts }
},
}
const result = await searchFirefliesMcp(client, {
...input,
limit: 1,
native: { provider: 'fireflies', query: 'launch', cursor: '10' },
})
expect(result.documents).toHaveLength(1)
expect(result.documents[0]).toMatchObject({
id: 'meeting-1',
eventStartAt: '2026-09-01T00:00:00.000Z',
})
expect(result.documents[0]?.modifiedAt).toBeUndefined()
expect(result.nextCursor).toBe('11')
expect(result.partial).toBe(false)
}
)

it('returns an empty Fireflies data page without reporting unavailable', async () => {
const client: ManagedSearchMcpClient = {
async call() {
return { data: [] }
},
}
const result = await searchFirefliesMcp(client, input)
expect(result.documents).toEqual([])
expect(result.nextCursor).toBeUndefined()
expect(result.partial).toBe(false)
})

it('keeps partial coverage and provider offsets when a Fireflies data page has invalid rows', async () => {
const client: ManagedSearchMcpClient = {
async call() {
return {
data: [
{ id: '../invalid', title: 'Invalid meeting' },
{ id: 'meeting-1', title: 'Planning' },
{ id: 'meeting-2', title: 'Next match' },
],
}
},
}
const result = await searchFirefliesMcp(client, {
...input,
limit: 1,
limit: 2,
native: { provider: 'fireflies', query: 'launch', cursor: '10' },
})
expect(result.documents[0]).toMatchObject({
id: 'meeting-1',
eventStartAt: '2026-09-01T00:00:00.000Z',
})
expect(result.documents[0]?.modifiedAt).toBeUndefined()
expect(result.nextCursor).toBe('11')
expect(result.documents.map((document) => document.id)).toEqual(['meeting-1'])
expect(result.nextCursor).toBe('12')
expect(result.partial).toBe(true)
})

it('keeps meetings earlier on a partial UTC end day and omits keyword scope from termless listings', async () => {
Expand Down Expand Up @@ -149,14 +194,26 @@ describe('meeting MCP provider wire contracts', () => {
expect(document.content).toContain(transcript)
})

it('fails on unknown Fireflies list formats rather than claiming zero matches', async () => {
const client = {
async call() {
return { answer: 'No matching meetings' }
},
it.each([
{ shape: 'unknown', response: { answer: 'No matching meetings' } },
{ shape: 'null data', response: { data: null } },
{ shape: 'text data', response: { data: '[]' } },
{ shape: 'object data', response: { data: {} } },
{
shape: 'malformed transcripts with a data array',
response: { transcripts: 'invalid', data: [] },
},
])(
'rejects $shape Fireflies list formats rather than claiming zero matches',
async ({ response }) => {
const client: ManagedSearchMcpClient = {
async call() {
return response
},
}
await expect(searchFirefliesMcp(client, input)).rejects.toThrow('unsupported')
}
await expect(searchFirefliesMcp(client, input)).rejects.toThrow('unsupported')
})
)

it.each(['text', 'json', 'code_fence', 'oversized'] as const)(
'diagnoses unsupported Fireflies %s envelopes without logging private values or arbitrary keys',
Expand Down
Loading