@menutes/mcp-server 0.1.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/README.md +44 -0
- package/dist/api.d.ts +63 -0
- package/dist/api.js +66 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +18 -0
- package/dist/tools/get-recording.d.ts +3 -0
- package/dist/tools/get-recording.js +43 -0
- package/dist/tools/get-summary.d.ts +3 -0
- package/dist/tools/get-summary.js +32 -0
- package/dist/tools/get-transcript.d.ts +3 -0
- package/dist/tools/get-transcript.js +51 -0
- package/dist/tools/list-recordings.d.ts +3 -0
- package/dist/tools/list-recordings.js +59 -0
- package/dist/tools/search-recordings.d.ts +3 -0
- package/dist/tools/search-recordings.js +57 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @menutes/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP server for accessing [Menutes](https://menutes.com) meeting transcripts and summaries from Claude Code.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
1. Get an API key from [Settings](https://app.menutes.com/settings?tab=api-keys)
|
|
8
|
+
|
|
9
|
+
2. Add to your MCP config:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"menutes": {
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["@menutes/mcp-server"],
|
|
17
|
+
"env": {
|
|
18
|
+
"MENUTES_API_KEY": "mnts_your_key_here"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Tools
|
|
26
|
+
|
|
27
|
+
| Tool | Description |
|
|
28
|
+
|------|-------------|
|
|
29
|
+
| `list_recordings` | List meetings with optional filtering by status and scope |
|
|
30
|
+
| `get_recording` | Get metadata for a specific recording |
|
|
31
|
+
| `get_transcript` | Get speaker-labeled transcript with timestamps |
|
|
32
|
+
| `get_summary` | Get AI-generated summary with action items |
|
|
33
|
+
| `search_recordings` | Search recordings by title |
|
|
34
|
+
|
|
35
|
+
## Environment Variables
|
|
36
|
+
|
|
37
|
+
| Variable | Required | Default | Description |
|
|
38
|
+
|----------|----------|---------|-------------|
|
|
39
|
+
| `MENUTES_API_KEY` | Yes | - | API key (starts with `mnts_`) |
|
|
40
|
+
| `MENUTES_BASE_URL` | No | `https://app.menutes.com` | API base URL |
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface Recording {
|
|
2
|
+
id: string;
|
|
3
|
+
meetingTitle: string | null;
|
|
4
|
+
status: "UPLOADING" | "PROCESSING" | "COMPLETED" | "FAILED";
|
|
5
|
+
duration: number | null;
|
|
6
|
+
speakerCount: number | null;
|
|
7
|
+
sharingScope: string;
|
|
8
|
+
createdAt: string;
|
|
9
|
+
updatedAt: string;
|
|
10
|
+
processingPhase: string | null;
|
|
11
|
+
sourceType: string;
|
|
12
|
+
user: {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string | null;
|
|
15
|
+
};
|
|
16
|
+
team: {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
} | null;
|
|
20
|
+
isOwner: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface RecordingContent {
|
|
23
|
+
transcription: string | null;
|
|
24
|
+
summary: string | null;
|
|
25
|
+
transcriptSegments: {
|
|
26
|
+
speaker: string;
|
|
27
|
+
text: string;
|
|
28
|
+
startTime: number | null;
|
|
29
|
+
endTime: number | null;
|
|
30
|
+
}[];
|
|
31
|
+
speakerNames: Record<string, string>;
|
|
32
|
+
notes: string | null;
|
|
33
|
+
}
|
|
34
|
+
export interface ListRecordingsResponse {
|
|
35
|
+
recordings: Recording[];
|
|
36
|
+
pagination: {
|
|
37
|
+
page: number;
|
|
38
|
+
limit: number;
|
|
39
|
+
total: number;
|
|
40
|
+
totalPages: number;
|
|
41
|
+
hasNextPage: boolean;
|
|
42
|
+
hasPrevPage: boolean;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export interface SearchResponse {
|
|
46
|
+
recordings: Recording[];
|
|
47
|
+
total: number;
|
|
48
|
+
}
|
|
49
|
+
export declare class MenutesApiClient {
|
|
50
|
+
private baseUrl;
|
|
51
|
+
private apiKey;
|
|
52
|
+
constructor(baseUrl: string, apiKey: string);
|
|
53
|
+
private request;
|
|
54
|
+
listRecordings(params?: {
|
|
55
|
+
page?: number;
|
|
56
|
+
limit?: number;
|
|
57
|
+
status?: string;
|
|
58
|
+
view?: string;
|
|
59
|
+
}): Promise<ListRecordingsResponse>;
|
|
60
|
+
getRecording(id: string): Promise<Recording>;
|
|
61
|
+
getRecordingContent(id: string): Promise<RecordingContent>;
|
|
62
|
+
searchRecordings(query: string, limit?: number): Promise<SearchResponse>;
|
|
63
|
+
}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export class MenutesApiClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
apiKey;
|
|
4
|
+
constructor(baseUrl, apiKey) {
|
|
5
|
+
this.baseUrl = baseUrl;
|
|
6
|
+
this.apiKey = apiKey;
|
|
7
|
+
}
|
|
8
|
+
async request(path, params) {
|
|
9
|
+
const url = new URL(path, this.baseUrl);
|
|
10
|
+
if (params) {
|
|
11
|
+
for (const [key, value] of Object.entries(params)) {
|
|
12
|
+
if (value !== undefined && value !== null) {
|
|
13
|
+
url.searchParams.set(key, String(value));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
let response;
|
|
18
|
+
try {
|
|
19
|
+
response = await fetch(url.toString(), {
|
|
20
|
+
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new Error(`Could not connect to Menutes API at ${this.baseUrl}`);
|
|
25
|
+
}
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
if (response.status === 401) {
|
|
28
|
+
throw new Error("Invalid API key. Check your MENUTES_API_KEY.");
|
|
29
|
+
}
|
|
30
|
+
if (response.status === 403) {
|
|
31
|
+
throw new Error("You don't have access to this recording.");
|
|
32
|
+
}
|
|
33
|
+
if (response.status === 404) {
|
|
34
|
+
throw new Error("Recording not found.");
|
|
35
|
+
}
|
|
36
|
+
if (response.status === 429) {
|
|
37
|
+
throw new Error("Rate limit exceeded (1000 req/hour). Try again later.");
|
|
38
|
+
}
|
|
39
|
+
const body = await response.text();
|
|
40
|
+
let message;
|
|
41
|
+
try {
|
|
42
|
+
message = JSON.parse(body).error || body;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
message = body || `HTTP ${response.status}`;
|
|
46
|
+
}
|
|
47
|
+
throw new Error(`Menutes API error: ${message}`);
|
|
48
|
+
}
|
|
49
|
+
return (await response.json());
|
|
50
|
+
}
|
|
51
|
+
async listRecordings(params) {
|
|
52
|
+
return this.request("/api/v1/recordings", params);
|
|
53
|
+
}
|
|
54
|
+
async getRecording(id) {
|
|
55
|
+
return this.request(`/api/v1/recordings/${encodeURIComponent(id)}`);
|
|
56
|
+
}
|
|
57
|
+
async getRecordingContent(id) {
|
|
58
|
+
return this.request(`/api/v1/recordings/${encodeURIComponent(id)}/content`);
|
|
59
|
+
}
|
|
60
|
+
async searchRecordings(query, limit) {
|
|
61
|
+
const params = { q: query };
|
|
62
|
+
if (limit !== undefined)
|
|
63
|
+
params.limit = limit;
|
|
64
|
+
return this.request("/api/v1/recordings/search", params);
|
|
65
|
+
}
|
|
66
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { MenutesApiClient } from "./api.js";
|
|
4
|
+
import { createServer } from "./server.js";
|
|
5
|
+
const apiKey = process.env.MENUTES_API_KEY;
|
|
6
|
+
if (!apiKey) {
|
|
7
|
+
console.error("MENUTES_API_KEY environment variable is required");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
if (!apiKey.startsWith("mnts_")) {
|
|
11
|
+
console.error("MENUTES_API_KEY must start with 'mnts_'");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
const baseUrl = process.env.MENUTES_BASE_URL || "https://app.menutes.com";
|
|
15
|
+
const api = new MenutesApiClient(baseUrl, apiKey);
|
|
16
|
+
const server = createServer(api);
|
|
17
|
+
const transport = new StdioServerTransport();
|
|
18
|
+
await server.connect(transport);
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerListRecordings } from "./tools/list-recordings.js";
|
|
3
|
+
import { registerGetRecording } from "./tools/get-recording.js";
|
|
4
|
+
import { registerGetTranscript } from "./tools/get-transcript.js";
|
|
5
|
+
import { registerGetSummary } from "./tools/get-summary.js";
|
|
6
|
+
import { registerSearchRecordings } from "./tools/search-recordings.js";
|
|
7
|
+
export function createServer(api) {
|
|
8
|
+
const server = new McpServer({
|
|
9
|
+
name: "menutes",
|
|
10
|
+
version: "0.1.0",
|
|
11
|
+
});
|
|
12
|
+
registerListRecordings(server, api);
|
|
13
|
+
registerGetRecording(server, api);
|
|
14
|
+
registerGetTranscript(server, api);
|
|
15
|
+
registerGetSummary(server, api);
|
|
16
|
+
registerSearchRecordings(server, api);
|
|
17
|
+
return server;
|
|
18
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerGetRecording(server, api) {
|
|
3
|
+
server.tool("get_recording", "Get detailed metadata for a specific Menutes recording including title, date, duration, speaker count, status, and sharing scope.", {
|
|
4
|
+
id: z.string().describe("The recording ID"),
|
|
5
|
+
}, async ({ id }) => {
|
|
6
|
+
try {
|
|
7
|
+
const r = await api.getRecording(id);
|
|
8
|
+
const duration = r.duration
|
|
9
|
+
? `${Math.floor(r.duration / 60)}m ${r.duration % 60}s`
|
|
10
|
+
: "unknown";
|
|
11
|
+
const date = new Date(r.createdAt).toLocaleString("en-GB", {
|
|
12
|
+
day: "numeric",
|
|
13
|
+
month: "short",
|
|
14
|
+
year: "numeric",
|
|
15
|
+
hour: "2-digit",
|
|
16
|
+
minute: "2-digit",
|
|
17
|
+
});
|
|
18
|
+
const text = [
|
|
19
|
+
`**${r.meetingTitle || "Untitled"}**`,
|
|
20
|
+
`Date: ${date}`,
|
|
21
|
+
`Duration: ${duration}`,
|
|
22
|
+
`Speakers: ${r.speakerCount ?? "unknown"}`,
|
|
23
|
+
`Status: ${r.status}`,
|
|
24
|
+
`Sharing: ${r.sharingScope}`,
|
|
25
|
+
`Source: ${r.sourceType}`,
|
|
26
|
+
`Owner: ${r.user.name || r.user.id}${r.team ? ` (${r.team.name})` : ""}`,
|
|
27
|
+
`ID: ${r.id}`,
|
|
28
|
+
].join("\n");
|
|
29
|
+
return { content: [{ type: "text", text }] };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerGetSummary(server, api) {
|
|
3
|
+
server.tool("get_summary", "Get the AI-generated summary of a Menutes recording including discussion points, decisions, and action items.", {
|
|
4
|
+
id: z.string().describe("The recording ID"),
|
|
5
|
+
}, async ({ id }) => {
|
|
6
|
+
try {
|
|
7
|
+
const content = await api.getRecordingContent(id);
|
|
8
|
+
if (!content.summary) {
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: "No summary available for this recording.",
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return { content: [{ type: "text", text: content.summary }] };
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: "text",
|
|
25
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
function formatTime(seconds) {
|
|
3
|
+
if (seconds === null || seconds === undefined)
|
|
4
|
+
return "??:??";
|
|
5
|
+
const m = Math.floor(seconds / 60);
|
|
6
|
+
const s = Math.floor(seconds % 60);
|
|
7
|
+
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
8
|
+
}
|
|
9
|
+
export function registerGetTranscript(server, api) {
|
|
10
|
+
server.tool("get_transcript", "Get the full speaker-labeled transcript with timestamps for a Menutes recording. For long meetings, consider using get_summary first.", {
|
|
11
|
+
id: z.string().describe("The recording ID"),
|
|
12
|
+
}, async ({ id }) => {
|
|
13
|
+
try {
|
|
14
|
+
const content = await api.getRecordingContent(id);
|
|
15
|
+
if (!content.transcriptSegments ||
|
|
16
|
+
content.transcriptSegments.length === 0) {
|
|
17
|
+
if (content.transcription) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: "text", text: content.transcription }],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
content: [
|
|
24
|
+
{
|
|
25
|
+
type: "text",
|
|
26
|
+
text: "No transcript available for this recording.",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const names = content.speakerNames || {};
|
|
32
|
+
const lines = content.transcriptSegments.map((seg) => {
|
|
33
|
+
const name = names[seg.speaker] || seg.speaker;
|
|
34
|
+
const time = formatTime(seg.startTime);
|
|
35
|
+
return `[${name}] (${time}): ${seg.text}`;
|
|
36
|
+
});
|
|
37
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return {
|
|
41
|
+
content: [
|
|
42
|
+
{
|
|
43
|
+
type: "text",
|
|
44
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
isError: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerListRecordings(server, api) {
|
|
3
|
+
server.tool("list_recordings", "List your Menutes meeting recordings with optional filtering. Returns titles, dates, durations, and IDs for further querying.", {
|
|
4
|
+
page: z
|
|
5
|
+
.number()
|
|
6
|
+
.int()
|
|
7
|
+
.positive()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Page number (default: 1)"),
|
|
10
|
+
limit: z
|
|
11
|
+
.number()
|
|
12
|
+
.int()
|
|
13
|
+
.min(1)
|
|
14
|
+
.max(100)
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Results per page (default: 20, max: 100)"),
|
|
17
|
+
status: z
|
|
18
|
+
.enum(["UPLOADING", "PROCESSING", "COMPLETED", "FAILED"])
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Filter by recording status"),
|
|
21
|
+
view: z
|
|
22
|
+
.enum(["my", "team", "organization", "all"])
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Scope: my (own), team (team-shared), organization (org-wide), all (admin)"),
|
|
25
|
+
}, async (params) => {
|
|
26
|
+
try {
|
|
27
|
+
const result = await api.listRecordings(params);
|
|
28
|
+
const lines = result.recordings.map((r) => {
|
|
29
|
+
const duration = r.duration
|
|
30
|
+
? `${Math.floor(r.duration / 60)}m ${r.duration % 60}s`
|
|
31
|
+
: "unknown";
|
|
32
|
+
const date = new Date(r.createdAt).toLocaleDateString("en-GB", {
|
|
33
|
+
day: "numeric",
|
|
34
|
+
month: "short",
|
|
35
|
+
year: "numeric",
|
|
36
|
+
});
|
|
37
|
+
return `- **${r.meetingTitle || "Untitled"}** (${date}, ${duration}, ${r.speakerCount ?? "?"} speakers) [${r.status}]\n ID: ${r.id}`;
|
|
38
|
+
});
|
|
39
|
+
const { pagination: p } = result;
|
|
40
|
+
const header = `Found ${p.total} recording(s) — page ${p.page}/${p.totalPages}`;
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{ type: "text", text: `${header}\n\n${lines.join("\n")}` },
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerSearchRecordings(server, api) {
|
|
3
|
+
server.tool("search_recordings", "Search Menutes recordings by title. Returns matching recordings with IDs for further querying.", {
|
|
4
|
+
query: z.string().describe("Search query to match against titles"),
|
|
5
|
+
limit: z
|
|
6
|
+
.number()
|
|
7
|
+
.int()
|
|
8
|
+
.min(1)
|
|
9
|
+
.max(50)
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Max results (default: 10, max: 50)"),
|
|
12
|
+
}, async ({ query, limit }) => {
|
|
13
|
+
try {
|
|
14
|
+
const result = await api.searchRecordings(query, limit);
|
|
15
|
+
if (result.recordings.length === 0) {
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: `No recordings found matching "${query}".`,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const lines = result.recordings.map((r) => {
|
|
26
|
+
const date = new Date(r.createdAt).toLocaleDateString("en-GB", {
|
|
27
|
+
day: "numeric",
|
|
28
|
+
month: "short",
|
|
29
|
+
year: "numeric",
|
|
30
|
+
});
|
|
31
|
+
const duration = r.duration
|
|
32
|
+
? `${Math.floor(r.duration / 60)}m ${r.duration % 60}s`
|
|
33
|
+
: "unknown";
|
|
34
|
+
return `- **${r.meetingTitle || "Untitled"}** (${date}, ${duration})\n ID: ${r.id}`;
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: `Found ${result.total} result(s) for "${query}":\n\n${lines.join("\n")}`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return {
|
|
47
|
+
content: [
|
|
48
|
+
{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
isError: true,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@menutes/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for accessing Menutes meeting transcripts and summaries from Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"menutes-mcp-server": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc && chmod +x dist/index.js",
|
|
14
|
+
"prepare": "npm run build",
|
|
15
|
+
"dev": "tsc --watch"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mcp",
|
|
19
|
+
"menutes",
|
|
20
|
+
"meetings",
|
|
21
|
+
"transcription",
|
|
22
|
+
"claude-code",
|
|
23
|
+
"model-context-protocol"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
31
|
+
"zod": "^3.24.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.0.0",
|
|
35
|
+
"typescript": "^5.7.0"
|
|
36
|
+
}
|
|
37
|
+
}
|