@c20020207/fathom-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ nodejs 22.14.0
package/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Fathom MCP
2
+
3
+ MCP server for [Fathom AI](https://fathom.video) — search meetings, get transcripts and summaries from Claude Code (or any MCP client).
4
+
5
+ ## Setup
6
+
7
+ ### 1. Get your Fathom API key
8
+
9
+ Go to [Fathom settings](https://fathom.video/settings) → API Access → generate a key.
10
+
11
+ ### 2. Add to Claude Code
12
+
13
+ ```bash
14
+ claude mcp add fathom -e FATHOM_API_KEY=your-key-here -- npx fathom-mcp
15
+ ```
16
+
17
+ That's it. Restart Claude Code and the tools are available.
18
+
19
+ ## Tools
20
+
21
+ | Tool | Description |
22
+ |------|-------------|
23
+ | `list_meetings` | List and filter meetings by date range, recorder, team. Optionally includes summaries and action items. |
24
+ | `get_transcript` | Get the full speaker-attributed transcript with timestamps for a recording. |
25
+ | `get_summary` | Get the AI-generated markdown summary for a recording. |
26
+
27
+ ### Example usage in Claude Code
28
+
29
+ > "Show me my meetings from last week"
30
+
31
+ > "Get the transcript from my meeting with Acme Corp"
32
+
33
+ > "Summarize my last 3 meetings"
34
+
35
+ ## API reference
36
+
37
+ Built on the [Fathom API](https://developers.fathom.ai/). Uses `X-Api-Key` header auth and cursor-based pagination.
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@c20020207/fathom-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Fathom AI - search meetings, get transcripts and summaries",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "bin": {
8
+ "fathom-mcp": "src/index.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node src/index.js",
12
+ "dev": "node --watch src/index.js"
13
+ },
14
+ "keywords": ["mcp", "fathom", "ai", "meetings", "transcripts"],
15
+ "license": "MIT",
16
+ "dependencies": {
17
+ "@modelcontextprotocol/sdk": "^1.12.1"
18
+ }
19
+ }
package/src/index.js ADDED
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+
6
+ const API_BASE = "https://api.fathom.ai/external/v1";
7
+
8
+ function getApiKey() {
9
+ const key = process.env.FATHOM_API_KEY;
10
+ if (!key) {
11
+ throw new Error("FATHOM_API_KEY environment variable is required");
12
+ }
13
+ return key;
14
+ }
15
+
16
+ async function fathomFetch(path, params = {}) {
17
+ const url = new URL(`${API_BASE}${path}`);
18
+ for (const [key, value] of Object.entries(params)) {
19
+ if (value !== undefined && value !== null && value !== "") {
20
+ if (Array.isArray(value)) {
21
+ for (const v of value) {
22
+ url.searchParams.append(`${key}[]`, v);
23
+ }
24
+ } else {
25
+ url.searchParams.set(key, String(value));
26
+ }
27
+ }
28
+ }
29
+
30
+ const response = await fetch(url.toString(), {
31
+ headers: { "X-Api-Key": getApiKey() },
32
+ });
33
+
34
+ if (!response.ok) {
35
+ const body = await response.text();
36
+ throw new Error(`Fathom API ${response.status}: ${body}`);
37
+ }
38
+
39
+ return response.json();
40
+ }
41
+
42
+ const server = new McpServer({
43
+ name: "fathom-mcp",
44
+ version: "1.0.0",
45
+ });
46
+
47
+ // Tool: List/search meetings
48
+ server.tool(
49
+ "list_meetings",
50
+ "List and filter Fathom meetings. Supports filtering by date range, recorder email, team, and invitee domains. Returns meeting metadata including title, URL, participants, and timestamps.",
51
+ {
52
+ cursor: z
53
+ .string()
54
+ .optional()
55
+ .describe("Pagination cursor from previous response"),
56
+ created_after: z
57
+ .string()
58
+ .optional()
59
+ .describe("ISO 8601 datetime - only meetings created after this time"),
60
+ created_before: z
61
+ .string()
62
+ .optional()
63
+ .describe("ISO 8601 datetime - only meetings created before this time"),
64
+ recorded_by: z
65
+ .array(z.string())
66
+ .optional()
67
+ .describe("Filter by recorder email(s)"),
68
+ teams: z
69
+ .array(z.string())
70
+ .optional()
71
+ .describe("Filter by team name(s)"),
72
+ include_summary: z
73
+ .boolean()
74
+ .optional()
75
+ .describe("Include meeting summary in response"),
76
+ include_action_items: z
77
+ .boolean()
78
+ .optional()
79
+ .describe("Include action items in response"),
80
+ },
81
+ async (args) => {
82
+ const data = await fathomFetch("/meetings", {
83
+ cursor: args.cursor,
84
+ created_after: args.created_after,
85
+ created_before: args.created_before,
86
+ recorded_by: args.recorded_by,
87
+ teams: args.teams,
88
+ include_summary: args.include_summary,
89
+ include_action_items: args.include_action_items,
90
+ });
91
+
92
+ const meetings = data.items.map((m) => ({
93
+ recording_id: m.recording_id,
94
+ title: m.title,
95
+ meeting_title: m.meeting_title,
96
+ url: m.url,
97
+ share_url: m.share_url,
98
+ created_at: m.created_at,
99
+ scheduled_start_time: m.scheduled_start_time,
100
+ scheduled_end_time: m.scheduled_end_time,
101
+ recording_start_time: m.recording_start_time,
102
+ recording_end_time: m.recording_end_time,
103
+ recorded_by: m.recorded_by,
104
+ calendar_invitees: m.calendar_invitees,
105
+ ...(m.default_summary && { summary: m.default_summary }),
106
+ ...(m.action_items && { action_items: m.action_items }),
107
+ }));
108
+
109
+ const result = {
110
+ meetings,
111
+ next_cursor: data.next_cursor,
112
+ total_in_page: meetings.length,
113
+ };
114
+
115
+ return {
116
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
117
+ };
118
+ }
119
+ );
120
+
121
+ // Tool: Get transcript for a recording
122
+ server.tool(
123
+ "get_transcript",
124
+ "Get the full transcript of a Fathom meeting/recording. Returns speaker-attributed text with timestamps.",
125
+ {
126
+ recording_id: z
127
+ .string()
128
+ .describe("The recording ID (from list_meetings results)"),
129
+ },
130
+ async (args) => {
131
+ const data = await fathomFetch(
132
+ `/recordings/${args.recording_id}/transcript`
133
+ );
134
+
135
+ return {
136
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
137
+ };
138
+ }
139
+ );
140
+
141
+ // Tool: Get summary for a recording
142
+ server.tool(
143
+ "get_summary",
144
+ "Get the AI-generated summary of a Fathom meeting/recording. Returns markdown-formatted summary.",
145
+ {
146
+ recording_id: z
147
+ .string()
148
+ .describe("The recording ID (from list_meetings results)"),
149
+ },
150
+ async (args) => {
151
+ const data = await fathomFetch(
152
+ `/recordings/${args.recording_id}/summary`
153
+ );
154
+
155
+ return {
156
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
157
+ };
158
+ }
159
+ );
160
+
161
+ const transport = new StdioServerTransport();
162
+ await server.connect(transport);