Skip to content

Commit 66050bd

Browse files
release: 4.1.295 (#16)
* feat(mcp): customize MCP outputs (#15) * release: 4.2.0 --------- Co-authored-by: batuhan <[email protected]> Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent 58d11be commit 66050bd

20 files changed

+973
-13
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "4.1.293"
2+
".": "4.2.0"
33
}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## 4.2.0 (2025-10-16)
4+
5+
Full Changelog: [v4.1.293...v4.2.0](https://github.com/beeper/desktop-api-js/compare/v4.1.293...v4.2.0)
6+
7+
### Features
8+
9+
* **mcp:** customize MCP outputs ([#15](https://github.com/beeper/desktop-api-js/issues/15)) ([21f3016](https://github.com/beeper/desktop-api-js/commit/21f30161ea06481f442648d03fd904a4e8395e99))
10+
311
## 4.1.293 (2025-10-16)
412

513
Full Changelog: [v0.1.5...v4.1.293](https://github.com/beeper/desktop-api-js/compare/v0.1.5...v4.1.293)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@beeper/desktop-api",
3-
"version": "4.1.293",
3+
"version": "4.2.0",
44
"description": "The official TypeScript library for the Beeper Desktop API",
55
"author": "Beeper Desktop <[email protected]>",
66
"types": "dist/index.d.ts",

packages/mcp-server/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@beeper/desktop-mcp",
3-
"version": "4.1.293",
3+
"version": "4.2.0",
44
"description": "The official MCP Server for the Beeper Desktop API",
55
"author": "Beeper Desktop <[email protected]>",
66
"types": "dist/index.d.ts",
@@ -35,6 +35,7 @@
3535
"@modelcontextprotocol/sdk": "^1.11.5",
3636
"@valtown/deno-http-worker": "^0.0.21",
3737
"cors": "^2.8.5",
38+
"date-fns": "^4.1.0",
3839
"express": "^5.1.0",
3940
"jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz",
4041
"qs": "^6.14.0",
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { HandlerFunction } from '../tools/types';
2+
import { asMarkdownContentResult } from './utils';
3+
4+
export const handler: HandlerFunction = async (client) => {
5+
const accounts = await client.accounts.list();
6+
if (!accounts || accounts.length === 0)
7+
throw new Error('No accounts found. This should never happen, please contact [email protected].');
8+
const lines: string[] = [];
9+
lines.push('# Accounts');
10+
for (const acc of accounts) {
11+
if (!acc.user) {
12+
lines.push(`\n## ${acc.network}`);
13+
lines.push(`**Account ID**: \`${acc.accountID}\``);
14+
lines.push('**User**: Unknown');
15+
continue;
16+
}
17+
18+
const name = acc.user.fullName || acc.user.username || acc.user.id;
19+
lines.push(`\n## ${acc.network}`);
20+
lines.push(`**Account ID**: \`${acc.accountID}\``);
21+
lines.push(`**User**: ${name}`);
22+
if (acc.user.email) lines.push(`**Email**: ${acc.user.email}`);
23+
if (acc.user.phoneNumber) lines.push(`**Phone**: ${acc.user.phoneNumber}`);
24+
}
25+
lines.push('\n# Using this information\n');
26+
lines.push('- Pass accountIDs to narrow chat/message queries when known.');
27+
return asMarkdownContentResult(lines);
28+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { HandlerFunction } from '../tools/types';
2+
import { asMarkdownContentResult, formatChatToMarkdown } from './utils';
3+
4+
export const handler: HandlerFunction = async (client, args) => {
5+
const { chatID, ...queryParams } = args as any;
6+
const chat = await client.chats.retrieve(chatID, queryParams);
7+
8+
const lines: string[] = [];
9+
if (!chat) {
10+
lines.push('Chat not found.');
11+
return asMarkdownContentResult(lines);
12+
}
13+
lines.push(formatChatToMarkdown(chat, undefined));
14+
lines.push('\n# Using this information\n');
15+
lines.push('- Use search_messages to find specific content in this chat.');
16+
lines.push('- Link the "open" link to the user to allow them to view the chat in Beeper Desktop.');
17+
return asMarkdownContentResult(lines);
18+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { Endpoint, HandlerFunction } from '../tools';
2+
3+
import { handler as get_accounts } from './get-accounts';
4+
import { handler as open_in_app } from './open-app';
5+
import { handler as search } from './search';
6+
import { handler as get_chat } from './get-chat';
7+
import { handler as search_chats } from './search-chats';
8+
import { handler as search_messages } from './search-messages';
9+
import { handler as send_message } from './send-message';
10+
11+
const HANDLER_OVERRIDES: Record<string, HandlerFunction> = {
12+
get_accounts,
13+
open_in_app,
14+
focus_app: open_in_app,
15+
search,
16+
get_chat,
17+
search_chats,
18+
search_messages,
19+
send_message,
20+
};
21+
22+
export function mapEndpoint(endpoint: Endpoint): Endpoint {
23+
const handler = HANDLER_OVERRIDES[endpoint.tool.name];
24+
if (!handler) return endpoint;
25+
return {
26+
...endpoint,
27+
handler,
28+
};
29+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { HandlerFunction } from '../tools/types';
2+
import { asMarkdownContentResult, formatChatToMarkdown } from './utils';
3+
4+
export const handler: HandlerFunction = async (client, args) => {
5+
const body = args as any;
6+
const output = await client.chats.search(body);
7+
8+
const lines: string[] = [];
9+
lines.push('# Chats');
10+
11+
const items = output.items || [];
12+
const hasMore = !!output.hasMore;
13+
14+
if (hasMore) {
15+
lines.push(`\nShowing ${items.length} chats (more available)`);
16+
if (output.oldestCursor) {
17+
lines.push(`Next page (older): cursor='${output.oldestCursor}', direction='before'`);
18+
}
19+
if (output.newestCursor) {
20+
lines.push(`Previous page (newer): cursor='${output.newestCursor}', direction='after'`);
21+
}
22+
} else if (items.length > 0) {
23+
lines.push(`\nShowing ${items.length} chat${items.length === 1 ? '' : 's'}`);
24+
}
25+
26+
if (items.length === 0) {
27+
lines.push('\nNo chats found.');
28+
} else {
29+
for (const chatWithPreview of items) {
30+
lines.push(formatChatToMarkdown(chatWithPreview, undefined));
31+
const preview = (chatWithPreview as any).preview;
32+
if (preview) {
33+
lines.push(`**Last message**: ${preview.text || '(no text)'}`);
34+
if (preview.senderName) {
35+
lines.push(`**From**: ${preview.senderName}`);
36+
}
37+
lines.push(`**Timestamp**: ${preview.timestamp}`);
38+
}
39+
}
40+
}
41+
lines.push('\n# Using this information\n');
42+
lines.push(
43+
'- Pass the "chatID" to get_chat or search_messages for details about a chat, or send_message to send a message to a chat.',
44+
);
45+
lines.push('- Link the "open" link to the user to allow them to view the chat in Beeper Desktop.');
46+
return asMarkdownContentResult(lines);
47+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { asTextContentResult, type HandlerFunction } from '../tools/types';
2+
import { mapMessagesToText } from './utils';
3+
4+
export const handler: HandlerFunction = async (client, args) => {
5+
const body = args as any;
6+
const output = await client.messages.search(body);
7+
8+
const lines: string[] = [];
9+
lines.push('# Messages');
10+
11+
const items = (output as any).items || [];
12+
const hasMore = !!(output as any).hasMore;
13+
14+
if (hasMore) {
15+
lines.push(`\nShowing ${items.length} messages (more available)`);
16+
if ((output as any).oldestCursor) {
17+
lines.push(`Next page (older): cursor='${(output as any).oldestCursor}', direction='before'`);
18+
}
19+
if ((output as any).newestCursor) {
20+
lines.push(`Previous page (newer): cursor='${(output as any).newestCursor}', direction='after'`);
21+
}
22+
} else if (items.length > 0) {
23+
lines.push(`\nShowing ${items.length} message${items.length === 1 ? '' : 's'}`);
24+
}
25+
26+
if (items.length === 0) {
27+
lines.push('\nNo messages found.');
28+
} else {
29+
lines.push(mapMessagesToText(output as any, body, undefined));
30+
}
31+
32+
return asTextContentResult(lines.join('\n'));
33+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { asTextContentResult, type HandlerFunction } from '../tools/types';
2+
3+
export const handler: HandlerFunction = async (client, args) => {
4+
const body = args as any;
5+
const output = await client.focus(body);
6+
7+
const lines: string[] = [];
8+
if (output.success) {
9+
lines.push('Beeper was opened.');
10+
if (body?.chatID) {
11+
const chatRef = String(body.chatID);
12+
lines.push(`Focused chat: ${chatRef}`);
13+
}
14+
if (body?.draftText) lines.push(`Draft text populated: ${body.draftText}`);
15+
if (body?.draftAttachmentPath) lines.push(`Draft attachment populated: ${body.draftAttachmentPath}`);
16+
} else {
17+
lines.push('Failed to open Beeper.');
18+
}
19+
return asTextContentResult(lines.join('\n'));
20+
};

0 commit comments

Comments
 (0)