fireflies-mcp-server
Version:
MCP server for Fireflies.ai API integration
362 lines (333 loc) • 9.34 kB
text/typescript
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// Fireflies API client
class FirefliesClient {
private apiKey: string;
private baseUrl = "https://api.fireflies.ai/graphql";
constructor(apiKey: string) {
this.apiKey = apiKey;
}
private async makeRequest(query: string, variables: any = {}) {
const response = await fetch(this.baseUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.apiKey}`,
},
body: JSON.stringify({
query,
variables,
}),
});
if (!response.ok) {
throw new Error(`Fireflies API error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
if (data.errors) {
throw new Error(`GraphQL errors: ${JSON.stringify(data.errors)}`);
}
return data.data;
}
async getTranscripts(limit: number = 10, fromDate?: string, toDate?: string) {
const query = `
query GetTranscripts($limit: Int, $fromDate: DateTime, $toDate: DateTime, $mine: Boolean) {
transcripts(limit: $limit, fromDate: $fromDate, toDate: $toDate, mine: $mine) {
id
title
date
duration
host_email
participants
transcript_url
summary {
overview
shorthand_bullet
action_items
keywords
outline
bullet_gist
short_summary
}
}
}
`;
return this.makeRequest(query, { limit, fromDate, toDate, mine: true });
}
async getTranscriptDetails(transcriptId: string) {
const query = `
query GetTranscript($transcriptId: String!) {
transcript(id: $transcriptId) {
id
title
date
duration
host_email
participants
transcript_url
sentences {
text
speaker_name
start_time
end_time
}
summary {
overview
shorthand_bullet
action_items
keywords
outline
bullet_gist
short_summary
}
}
}
`;
return this.makeRequest(query, { transcriptId });
}
async searchTranscripts(query: string, limit: number = 10) {
const searchQuery = `
query SearchTranscripts($title: String, $limit: Int, $mine: Boolean) {
transcripts(title: $title, limit: $limit, mine: $mine) {
id
title
date
duration
host_email
participants
summary {
overview
keywords
short_summary
}
}
}
`;
return this.makeRequest(searchQuery, { title: query, limit, mine: true });
}
async generateSummary(transcriptId: string, format: string = "bullet_points") {
const query = `
query GetSummary($transcriptId: String!) {
transcript(id: $transcriptId) {
id
title
summary {
overview
shorthand_bullet
action_items
keywords
outline
bullet_gist
short_summary
}
}
}
`;
const result = await this.makeRequest(query, { transcriptId });
const summary = result.transcript.summary;
if (format === "paragraph") {
return {
transcript_id: transcriptId,
title: result.transcript.title,
format: "paragraph",
summary: summary.overview,
};
} else {
return {
transcript_id: transcriptId,
title: result.transcript.title,
format: "bullet_points",
summary: {
overview: summary.overview,
bullet_points: summary.shorthand_bullet,
action_items: summary.action_items,
keywords: summary.keywords,
short_summary: summary.short_summary,
},
};
}
}
}
// MCP Server setup
const server = new Server(
{
name: "fireflies-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// Initialize Fireflies client
const apiKey = process.env.FIREFLIES_API_KEY;
if (!apiKey) {
console.error("FIREFLIES_API_KEY environment variable is required");
process.exit(1);
}
const firefliesClient = new FirefliesClient(apiKey);
// Register tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "fireflies_get_transcripts",
description: "Retrieve a list of meeting transcripts with optional filtering",
inputSchema: {
type: "object",
properties: {
limit: {
type: "number",
description: "Maximum number of transcripts to return (default: 10)",
default: 10,
},
from_date: {
type: "string",
description: "Start date in ISO format (YYYY-MM-DD)",
},
to_date: {
type: "string",
description: "End date in ISO format (YYYY-MM-DD)",
},
},
},
},
{
name: "fireflies_get_transcript_details",
description: "Get detailed information about a specific transcript",
inputSchema: {
type: "object",
properties: {
transcript_id: {
type: "string",
description: "ID of the transcript to retrieve",
},
},
required: ["transcript_id"],
},
},
{
name: "fireflies_search_transcripts",
description: "Search for transcripts containing specific keywords",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "Search query to find relevant transcripts",
},
limit: {
type: "number",
description: "Maximum number of transcripts to return (default: 10)",
default: 10,
},
},
required: ["query"],
},
},
{
name: "fireflies_generate_summary",
description: "Generate a summary of a meeting transcript",
inputSchema: {
type: "object",
properties: {
transcript_id: {
type: "string",
description: "ID of the transcript to summarize",
},
format: {
type: "string",
description: "Format of the summary ('bullet_points' or 'paragraph')",
enum: ["bullet_points", "paragraph"],
default: "bullet_points",
},
},
required: ["transcript_id"],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "fireflies_get_transcripts": {
const { limit = 10, from_date, to_date } = args as any;
const result = await firefliesClient.getTranscripts(limit, from_date, to_date);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
case "fireflies_get_transcript_details": {
const { transcript_id } = args as any;
const result = await firefliesClient.getTranscriptDetails(transcript_id);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
case "fireflies_search_transcripts": {
const { query, limit = 10 } = args as any;
const result = await firefliesClient.searchTranscripts(query, limit);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
case "fireflies_generate_summary": {
const { transcript_id, format = "bullet_points" } = args as any;
const result = await firefliesClient.generateSummary(transcript_id, format);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
}
});
// Start the server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Fireflies MCP server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});