@beeper/desktop-mcp 0.1.2
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/LICENSE +7 -0
- package/README.md +252 -0
- package/code-tool-paths.cjs +6 -0
- package/code-tool-paths.cjs.map +1 -0
- package/code-tool-paths.d.cts +2 -0
- package/code-tool-paths.d.cts.map +1 -0
- package/code-tool-types.d.mts +14 -0
- package/code-tool-types.d.mts.map +1 -0
- package/code-tool-types.d.ts +14 -0
- package/code-tool-types.d.ts.map +1 -0
- package/code-tool-types.js +4 -0
- package/code-tool-types.js.map +1 -0
- package/code-tool-types.mjs +3 -0
- package/code-tool-types.mjs.map +1 -0
- package/code-tool-worker.d.mts +5 -0
- package/code-tool-worker.d.mts.map +1 -0
- package/code-tool-worker.d.ts +5 -0
- package/code-tool-worker.d.ts.map +1 -0
- package/code-tool-worker.js +45 -0
- package/code-tool-worker.js.map +1 -0
- package/code-tool-worker.mjs +40 -0
- package/code-tool-worker.mjs.map +1 -0
- package/code-tool.d.mts +12 -0
- package/code-tool.d.mts.map +1 -0
- package/code-tool.d.ts +12 -0
- package/code-tool.d.ts.map +1 -0
- package/code-tool.js +123 -0
- package/code-tool.js.map +1 -0
- package/code-tool.mjs +120 -0
- package/code-tool.mjs.map +1 -0
- package/compat.d.mts +58 -0
- package/compat.d.mts.map +1 -0
- package/compat.d.ts +58 -0
- package/compat.d.ts.map +1 -0
- package/compat.js +387 -0
- package/compat.js.map +1 -0
- package/compat.mjs +378 -0
- package/compat.mjs.map +1 -0
- package/dynamic-tools.d.mts +12 -0
- package/dynamic-tools.d.mts.map +1 -0
- package/dynamic-tools.d.ts +12 -0
- package/dynamic-tools.d.ts.map +1 -0
- package/dynamic-tools.js +135 -0
- package/dynamic-tools.js.map +1 -0
- package/dynamic-tools.mjs +132 -0
- package/dynamic-tools.mjs.map +1 -0
- package/filtering.d.mts +2 -0
- package/filtering.d.mts.map +1 -0
- package/filtering.d.ts +2 -0
- package/filtering.d.ts.map +1 -0
- package/filtering.js +20 -0
- package/filtering.js.map +1 -0
- package/filtering.mjs +13 -0
- package/filtering.mjs.map +1 -0
- package/headers.d.mts +4 -0
- package/headers.d.mts.map +1 -0
- package/headers.d.ts +4 -0
- package/headers.d.ts.map +1 -0
- package/headers.js +22 -0
- package/headers.js.map +1 -0
- package/headers.mjs +18 -0
- package/headers.mjs.map +1 -0
- package/http.d.mts +5 -0
- package/http.d.mts.map +1 -0
- package/http.d.ts +5 -0
- package/http.d.ts.map +1 -0
- package/http.js +127 -0
- package/http.js.map +1 -0
- package/http.mjs +119 -0
- package/http.mjs.map +1 -0
- package/index.d.mts +3 -0
- package/index.d.mts.map +1 -0
- package/index.d.ts +3 -0
- package/index.d.ts.map +1 -0
- package/index.js +91 -0
- package/index.js.map +1 -0
- package/index.mjs +89 -0
- package/index.mjs.map +1 -0
- package/options.d.mts +19 -0
- package/options.d.mts.map +1 -0
- package/options.d.ts +19 -0
- package/options.d.ts.map +1 -0
- package/options.js +417 -0
- package/options.js.map +1 -0
- package/options.mjs +410 -0
- package/options.mjs.map +1 -0
- package/package.json +206 -0
- package/server.d.mts +35 -0
- package/server.d.mts.map +1 -0
- package/server.d.ts +35 -0
- package/server.d.ts.map +1 -0
- package/server.js +151 -0
- package/server.js.map +1 -0
- package/server.mjs +137 -0
- package/server.mjs.map +1 -0
- package/src/code-tool-paths.cts +3 -0
- package/src/code-tool-types.ts +14 -0
- package/src/code-tool-worker.ts +46 -0
- package/src/code-tool.ts +144 -0
- package/src/compat.ts +483 -0
- package/src/dynamic-tools.ts +159 -0
- package/src/filtering.ts +14 -0
- package/src/headers.ts +23 -0
- package/src/http.ts +137 -0
- package/src/index.ts +108 -0
- package/src/options.ts +456 -0
- package/src/server.ts +184 -0
- package/src/stdio.ts +13 -0
- package/src/tools/accounts/get-accounts.ts +34 -0
- package/src/tools/app/open-app.ts +47 -0
- package/src/tools/chats/archive-chat.ts +42 -0
- package/src/tools/chats/get-chat.ts +46 -0
- package/src/tools/chats/search-chats.ts +101 -0
- package/src/tools/index.ts +89 -0
- package/src/tools/messages/get-attachment.ts +42 -0
- package/src/tools/messages/search-messages.ts +133 -0
- package/src/tools/messages/send-message.ts +46 -0
- package/src/tools/reminders/clear-chat-reminder.ts +38 -0
- package/src/tools/reminders/set-chat-reminder.ts +53 -0
- package/src/tools/types.ts +103 -0
- package/src/tools.ts +1 -0
- package/src/tsconfig.json +11 -0
- package/stdio.d.mts +3 -0
- package/stdio.d.mts.map +1 -0
- package/stdio.d.ts +3 -0
- package/stdio.d.ts.map +1 -0
- package/stdio.js +14 -0
- package/stdio.js.map +1 -0
- package/stdio.mjs +10 -0
- package/stdio.mjs.map +1 -0
- package/tools/accounts/get-accounts.d.mts +45 -0
- package/tools/accounts/get-accounts.d.mts.map +1 -0
- package/tools/accounts/get-accounts.d.ts +45 -0
- package/tools/accounts/get-accounts.d.ts.map +1 -0
- package/tools/accounts/get-accounts.js +31 -0
- package/tools/accounts/get-accounts.js.map +1 -0
- package/tools/accounts/get-accounts.mjs +27 -0
- package/tools/accounts/get-accounts.mjs.map +1 -0
- package/tools/app/open-app.d.mts +45 -0
- package/tools/app/open-app.d.mts.map +1 -0
- package/tools/app/open-app.d.ts +45 -0
- package/tools/app/open-app.d.ts.map +1 -0
- package/tools/app/open-app.js +43 -0
- package/tools/app/open-app.js.map +1 -0
- package/tools/app/open-app.mjs +39 -0
- package/tools/app/open-app.mjs.map +1 -0
- package/tools/chats/archive-chat.d.mts +45 -0
- package/tools/chats/archive-chat.d.mts.map +1 -0
- package/tools/chats/archive-chat.d.ts +45 -0
- package/tools/chats/archive-chat.d.ts.map +1 -0
- package/tools/chats/archive-chat.js +39 -0
- package/tools/chats/archive-chat.js.map +1 -0
- package/tools/chats/archive-chat.mjs +35 -0
- package/tools/chats/archive-chat.mjs.map +1 -0
- package/tools/chats/get-chat.d.mts +45 -0
- package/tools/chats/get-chat.d.mts.map +1 -0
- package/tools/chats/get-chat.d.ts +45 -0
- package/tools/chats/get-chat.d.ts.map +1 -0
- package/tools/chats/get-chat.js +41 -0
- package/tools/chats/get-chat.js.map +1 -0
- package/tools/chats/get-chat.mjs +37 -0
- package/tools/chats/get-chat.mjs.map +1 -0
- package/tools/chats/search-chats.d.mts +45 -0
- package/tools/chats/search-chats.d.mts.map +1 -0
- package/tools/chats/search-chats.d.ts +45 -0
- package/tools/chats/search-chats.d.ts.map +1 -0
- package/tools/chats/search-chats.js +90 -0
- package/tools/chats/search-chats.js.map +1 -0
- package/tools/chats/search-chats.mjs +86 -0
- package/tools/chats/search-chats.mjs.map +1 -0
- package/tools/index.d.mts +10 -0
- package/tools/index.d.mts.map +1 -0
- package/tools/index.d.ts +10 -0
- package/tools/index.d.ts.map +1 -0
- package/tools/index.js +73 -0
- package/tools/index.js.map +1 -0
- package/tools/index.mjs +66 -0
- package/tools/index.mjs.map +1 -0
- package/tools/messages/get-attachment.d.mts +45 -0
- package/tools/messages/get-attachment.d.mts.map +1 -0
- package/tools/messages/get-attachment.d.ts +45 -0
- package/tools/messages/get-attachment.d.ts.map +1 -0
- package/tools/messages/get-attachment.js +39 -0
- package/tools/messages/get-attachment.js.map +1 -0
- package/tools/messages/get-attachment.mjs +35 -0
- package/tools/messages/get-attachment.mjs.map +1 -0
- package/tools/messages/search-messages.d.mts +45 -0
- package/tools/messages/search-messages.d.mts.map +1 -0
- package/tools/messages/search-messages.d.ts +45 -0
- package/tools/messages/search-messages.d.ts.map +1 -0
- package/tools/messages/search-messages.js +121 -0
- package/tools/messages/search-messages.js.map +1 -0
- package/tools/messages/search-messages.mjs +117 -0
- package/tools/messages/search-messages.mjs.map +1 -0
- package/tools/messages/send-message.d.mts +45 -0
- package/tools/messages/send-message.d.mts.map +1 -0
- package/tools/messages/send-message.d.ts +45 -0
- package/tools/messages/send-message.d.ts.map +1 -0
- package/tools/messages/send-message.js +43 -0
- package/tools/messages/send-message.js.map +1 -0
- package/tools/messages/send-message.mjs +39 -0
- package/tools/messages/send-message.mjs.map +1 -0
- package/tools/reminders/clear-chat-reminder.d.mts +45 -0
- package/tools/reminders/clear-chat-reminder.d.mts.map +1 -0
- package/tools/reminders/clear-chat-reminder.d.ts +45 -0
- package/tools/reminders/clear-chat-reminder.d.ts.map +1 -0
- package/tools/reminders/clear-chat-reminder.js +35 -0
- package/tools/reminders/clear-chat-reminder.js.map +1 -0
- package/tools/reminders/clear-chat-reminder.mjs +31 -0
- package/tools/reminders/clear-chat-reminder.mjs.map +1 -0
- package/tools/reminders/set-chat-reminder.d.mts +45 -0
- package/tools/reminders/set-chat-reminder.d.mts.map +1 -0
- package/tools/reminders/set-chat-reminder.d.ts +45 -0
- package/tools/reminders/set-chat-reminder.d.ts.map +1 -0
- package/tools/reminders/set-chat-reminder.js +50 -0
- package/tools/reminders/set-chat-reminder.js.map +1 -0
- package/tools/reminders/set-chat-reminder.mjs +46 -0
- package/tools/reminders/set-chat-reminder.mjs.map +1 -0
- package/tools/types.d.mts +51 -0
- package/tools/types.d.mts.map +1 -0
- package/tools/types.d.ts +51 -0
- package/tools/types.d.ts.map +1 -0
- package/tools/types.js +46 -0
- package/tools/types.js.map +1 -0
- package/tools/types.mjs +42 -0
- package/tools/types.mjs.map +1 -0
- package/tools.d.mts +2 -0
- package/tools.d.mts.map +1 -0
- package/tools.d.ts +2 -0
- package/tools.d.ts.map +1 -0
- package/tools.js +18 -0
- package/tools.js.map +1 -0
- package/tools.mjs +2 -0
- package/tools.mjs.map +1 -0
package/src/server.ts
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
|
+
import { Endpoint, endpoints, HandlerFunction, query } from './tools';
|
|
6
|
+
import {
|
|
7
|
+
CallToolRequestSchema,
|
|
8
|
+
Implementation,
|
|
9
|
+
ListToolsRequestSchema,
|
|
10
|
+
Tool,
|
|
11
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
12
|
+
import { ClientOptions } from '@beeper/desktop-api';
|
|
13
|
+
import BeeperDesktop from '@beeper/desktop-api';
|
|
14
|
+
import {
|
|
15
|
+
applyCompatibilityTransformations,
|
|
16
|
+
ClientCapabilities,
|
|
17
|
+
defaultClientCapabilities,
|
|
18
|
+
knownClients,
|
|
19
|
+
parseEmbeddedJSON,
|
|
20
|
+
} from './compat';
|
|
21
|
+
import { dynamicTools } from './dynamic-tools';
|
|
22
|
+
import { codeTool } from './code-tool';
|
|
23
|
+
import { McpOptions } from './options';
|
|
24
|
+
|
|
25
|
+
export { McpOptions } from './options';
|
|
26
|
+
export { ClientType } from './compat';
|
|
27
|
+
export { Filter } from './tools';
|
|
28
|
+
export { ClientOptions } from '@beeper/desktop-api';
|
|
29
|
+
export { endpoints } from './tools';
|
|
30
|
+
|
|
31
|
+
export const newMcpServer = () =>
|
|
32
|
+
new McpServer(
|
|
33
|
+
{
|
|
34
|
+
name: 'beeper_desktop_api_api',
|
|
35
|
+
version: '0.1.2',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
capabilities: { tools: {}, logging: {} },
|
|
39
|
+
instructions:
|
|
40
|
+
'This MCP server provides access to your Beeper Desktop messages and chats. Use the search and find tools to locate messages and conversations, then use send_message to respond.',
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// Create server instance
|
|
45
|
+
export const server = newMcpServer();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initializes the provided MCP Server with the given tools and handlers.
|
|
49
|
+
* If not provided, the default client, tools and handlers will be used.
|
|
50
|
+
*/
|
|
51
|
+
export function initMcpServer(params: {
|
|
52
|
+
server: Server | McpServer;
|
|
53
|
+
clientOptions?: ClientOptions;
|
|
54
|
+
mcpOptions?: McpOptions;
|
|
55
|
+
}) {
|
|
56
|
+
const server = params.server instanceof McpServer ? params.server.server : params.server;
|
|
57
|
+
const mcpOptions = params.mcpOptions ?? {};
|
|
58
|
+
|
|
59
|
+
let providedEndpoints: Endpoint[] | null = null;
|
|
60
|
+
let endpointMap: Record<string, Endpoint> | null = null;
|
|
61
|
+
|
|
62
|
+
const initTools = (implementation?: Implementation) => {
|
|
63
|
+
if (implementation && (!mcpOptions.client || mcpOptions.client === 'infer')) {
|
|
64
|
+
mcpOptions.client =
|
|
65
|
+
implementation.name.toLowerCase().includes('claude') ? 'claude'
|
|
66
|
+
: implementation.name.toLowerCase().includes('cursor') ? 'cursor'
|
|
67
|
+
: undefined;
|
|
68
|
+
mcpOptions.capabilities = {
|
|
69
|
+
...(mcpOptions.client && knownClients[mcpOptions.client]),
|
|
70
|
+
...mcpOptions.capabilities,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
providedEndpoints = selectTools(endpoints, mcpOptions);
|
|
74
|
+
endpointMap = Object.fromEntries(providedEndpoints.map((endpoint) => [endpoint.tool.name, endpoint]));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const logAtLevel =
|
|
78
|
+
(level: 'debug' | 'info' | 'warning' | 'error') =>
|
|
79
|
+
(message: string, ...rest: unknown[]) => {
|
|
80
|
+
void server.sendLoggingMessage({
|
|
81
|
+
level,
|
|
82
|
+
data: { message, rest },
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
const logger = {
|
|
86
|
+
debug: logAtLevel('debug'),
|
|
87
|
+
info: logAtLevel('info'),
|
|
88
|
+
warn: logAtLevel('warning'),
|
|
89
|
+
error: logAtLevel('error'),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const client = new BeeperDesktop({
|
|
93
|
+
logger,
|
|
94
|
+
...params.clientOptions,
|
|
95
|
+
defaultHeaders: {
|
|
96
|
+
...params.clientOptions?.defaultHeaders,
|
|
97
|
+
'X-Stainless-MCP': 'true',
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
102
|
+
if (providedEndpoints === null) {
|
|
103
|
+
initTools(server.getClientVersion());
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
tools: providedEndpoints!.map((endpoint) => endpoint.tool),
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
111
|
+
if (endpointMap === null) {
|
|
112
|
+
initTools(server.getClientVersion());
|
|
113
|
+
}
|
|
114
|
+
const { name, arguments: args } = request.params;
|
|
115
|
+
const endpoint = endpointMap![name];
|
|
116
|
+
if (!endpoint) {
|
|
117
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return executeHandler(endpoint.tool, endpoint.handler, client, args, mcpOptions.capabilities);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Selects the tools to include in the MCP Server based on the provided options.
|
|
126
|
+
*/
|
|
127
|
+
export function selectTools(endpoints: Endpoint[], options?: McpOptions): Endpoint[] {
|
|
128
|
+
const filteredEndpoints = query(options?.filters ?? [], endpoints);
|
|
129
|
+
|
|
130
|
+
let includedTools = filteredEndpoints;
|
|
131
|
+
|
|
132
|
+
if (includedTools.length > 0) {
|
|
133
|
+
if (options?.includeDynamicTools) {
|
|
134
|
+
includedTools = dynamicTools(includedTools);
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
if (options?.includeAllTools) {
|
|
138
|
+
includedTools = endpoints;
|
|
139
|
+
} else if (options?.includeDynamicTools) {
|
|
140
|
+
includedTools = dynamicTools(endpoints);
|
|
141
|
+
} else if (options?.includeCodeTools) {
|
|
142
|
+
includedTools = [codeTool()];
|
|
143
|
+
} else {
|
|
144
|
+
includedTools = endpoints;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const capabilities = { ...defaultClientCapabilities, ...options?.capabilities };
|
|
149
|
+
return applyCompatibilityTransformations(includedTools, capabilities);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Runs the provided handler with the given client and arguments.
|
|
154
|
+
*/
|
|
155
|
+
export async function executeHandler(
|
|
156
|
+
tool: Tool,
|
|
157
|
+
handler: HandlerFunction,
|
|
158
|
+
client: BeeperDesktop,
|
|
159
|
+
args: Record<string, unknown> | undefined,
|
|
160
|
+
compatibilityOptions?: Partial<ClientCapabilities>,
|
|
161
|
+
) {
|
|
162
|
+
const options = { ...defaultClientCapabilities, ...compatibilityOptions };
|
|
163
|
+
if (!options.validJson && args) {
|
|
164
|
+
args = parseEmbeddedJSON(args, tool.inputSchema);
|
|
165
|
+
}
|
|
166
|
+
return await handler(client, args || {});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const readEnv = (env: string): string | undefined => {
|
|
170
|
+
if (typeof (globalThis as any).process !== 'undefined') {
|
|
171
|
+
return (globalThis as any).process.env?.[env]?.trim();
|
|
172
|
+
} else if (typeof (globalThis as any).Deno !== 'undefined') {
|
|
173
|
+
return (globalThis as any).Deno.env?.get?.(env)?.trim();
|
|
174
|
+
}
|
|
175
|
+
return;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const readEnvOrError = (env: string): string => {
|
|
179
|
+
let envValue = readEnv(env);
|
|
180
|
+
if (envValue === undefined) {
|
|
181
|
+
throw new Error(`Environment variable ${env} is not set`);
|
|
182
|
+
}
|
|
183
|
+
return envValue;
|
|
184
|
+
};
|
package/src/stdio.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
+
import { initMcpServer, newMcpServer } from './server';
|
|
3
|
+
import { McpOptions } from './options';
|
|
4
|
+
|
|
5
|
+
export const launchStdioServer = async (options: McpOptions) => {
|
|
6
|
+
const server = newMcpServer();
|
|
7
|
+
|
|
8
|
+
initMcpServer({ server, mcpOptions: options });
|
|
9
|
+
|
|
10
|
+
const transport = new StdioServerTransport();
|
|
11
|
+
await server.connect(transport);
|
|
12
|
+
console.error('MCP Server running on stdio');
|
|
13
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
import { Metadata, asTextContentResult } from '@beeper/desktop-mcp/tools/types';
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import BeeperDesktop from '@beeper/desktop-api';
|
|
7
|
+
|
|
8
|
+
export const metadata: Metadata = {
|
|
9
|
+
resource: 'accounts',
|
|
10
|
+
operation: 'read',
|
|
11
|
+
tags: ['accounts'],
|
|
12
|
+
httpMethod: 'get',
|
|
13
|
+
httpPath: '/v0/get-accounts',
|
|
14
|
+
operationId: 'get_accounts',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const tool: Tool = {
|
|
18
|
+
name: 'get_accounts',
|
|
19
|
+
description: 'List connected accounts on this device. Use to pick account context.',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {},
|
|
23
|
+
required: [],
|
|
24
|
+
},
|
|
25
|
+
annotations: {
|
|
26
|
+
readOnlyHint: true,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const handler = async (client: BeeperDesktop, args: Record<string, unknown> | undefined) => {
|
|
31
|
+
return asTextContentResult(await client.accounts.list());
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default { metadata, tool, handler };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
import { Metadata, asTextContentResult } from '@beeper/desktop-mcp/tools/types';
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import BeeperDesktop from '@beeper/desktop-api';
|
|
7
|
+
|
|
8
|
+
export const metadata: Metadata = {
|
|
9
|
+
resource: 'app',
|
|
10
|
+
operation: 'write',
|
|
11
|
+
tags: ['app'],
|
|
12
|
+
httpMethod: 'post',
|
|
13
|
+
httpPath: '/v0/open-app',
|
|
14
|
+
operationId: 'open_app',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const tool: Tool = {
|
|
18
|
+
name: 'open_app',
|
|
19
|
+
description: 'Open Beeper, optionally focusing a chat or message, or pre-filling a draft.',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
chatID: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description:
|
|
26
|
+
'Optional Beeper chat ID to focus after opening the app. If omitted, only opens/focuses the app.',
|
|
27
|
+
},
|
|
28
|
+
draftText: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Optional draft text to populate in the message input field.',
|
|
31
|
+
},
|
|
32
|
+
messageSortKey: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
description: 'Optional message sort key. Jumps to that message in the chat when opening.',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
required: [],
|
|
38
|
+
},
|
|
39
|
+
annotations: {},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const handler = async (client: BeeperDesktop, args: Record<string, unknown> | undefined) => {
|
|
43
|
+
const body = args as any;
|
|
44
|
+
return asTextContentResult(await client.app.focus(body));
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default { metadata, tool, handler };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
import { Metadata, asTextContentResult } from '@beeper/desktop-mcp/tools/types';
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import BeeperDesktop from '@beeper/desktop-api';
|
|
7
|
+
|
|
8
|
+
export const metadata: Metadata = {
|
|
9
|
+
resource: 'chats',
|
|
10
|
+
operation: 'write',
|
|
11
|
+
tags: ['chats'],
|
|
12
|
+
httpMethod: 'post',
|
|
13
|
+
httpPath: '/v0/archive-chat',
|
|
14
|
+
operationId: 'archive_chat',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const tool: Tool = {
|
|
18
|
+
name: 'archive_chat',
|
|
19
|
+
description: 'Archive or unarchive a chat.',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
chatID: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'The identifier of the chat to archive or unarchive',
|
|
26
|
+
},
|
|
27
|
+
archived: {
|
|
28
|
+
type: 'boolean',
|
|
29
|
+
description: 'True to archive, false to unarchive',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
required: ['chatID'],
|
|
33
|
+
},
|
|
34
|
+
annotations: {},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const handler = async (client: BeeperDesktop, args: Record<string, unknown> | undefined) => {
|
|
38
|
+
const body = args as any;
|
|
39
|
+
return asTextContentResult(await client.chats.archive(body));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default { metadata, tool, handler };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
import { Metadata, asTextContentResult } from '@beeper/desktop-mcp/tools/types';
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import BeeperDesktop from '@beeper/desktop-api';
|
|
7
|
+
|
|
8
|
+
export const metadata: Metadata = {
|
|
9
|
+
resource: 'chats',
|
|
10
|
+
operation: 'read',
|
|
11
|
+
tags: ['chats'],
|
|
12
|
+
httpMethod: 'get',
|
|
13
|
+
httpPath: '/v0/get-chat',
|
|
14
|
+
operationId: 'get_chat',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const tool: Tool = {
|
|
18
|
+
name: 'get_chat',
|
|
19
|
+
description: 'Get chat details: metadata, participants (limited), last activity.',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
chatID: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description:
|
|
26
|
+
"Unique identifier of the chat to retrieve. Not available for iMessage chats. Participants are limited by 'maxParticipantCount'.",
|
|
27
|
+
},
|
|
28
|
+
maxParticipantCount: {
|
|
29
|
+
type: 'integer',
|
|
30
|
+
description:
|
|
31
|
+
'Maximum number of participants to return. Use -1 for all; otherwise 0–500. Defaults to 20.',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: ['chatID'],
|
|
35
|
+
},
|
|
36
|
+
annotations: {
|
|
37
|
+
readOnlyHint: true,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const handler = async (client: BeeperDesktop, args: Record<string, unknown> | undefined) => {
|
|
42
|
+
const body = args as any;
|
|
43
|
+
return asTextContentResult(await client.chats.get(body));
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default { metadata, tool, handler };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
import { Metadata, asTextContentResult } from '@beeper/desktop-mcp/tools/types';
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import BeeperDesktop from '@beeper/desktop-api';
|
|
7
|
+
|
|
8
|
+
export const metadata: Metadata = {
|
|
9
|
+
resource: 'chats',
|
|
10
|
+
operation: 'read',
|
|
11
|
+
tags: ['chats'],
|
|
12
|
+
httpMethod: 'get',
|
|
13
|
+
httpPath: '/v0/search-chats',
|
|
14
|
+
operationId: 'search_chats',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const tool: Tool = {
|
|
18
|
+
name: 'search_chats',
|
|
19
|
+
description: 'Search chats by inbox, type, unread status, or text. Paginates.',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
accountIDs: {
|
|
24
|
+
type: 'array',
|
|
25
|
+
description: 'Provide an array of account IDs to filter chats from specific messaging accounts only',
|
|
26
|
+
items: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
cursor: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'Pagination cursor from previous response. Use with direction to navigate results',
|
|
33
|
+
},
|
|
34
|
+
direction: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description:
|
|
37
|
+
'Pagination direction: "after" for newer page, "before" for older page. Defaults to "before" when only cursor is provided.',
|
|
38
|
+
enum: ['after', 'before'],
|
|
39
|
+
},
|
|
40
|
+
inbox: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
description:
|
|
43
|
+
'Filter by inbox type: "primary" (non-archived, non-low-priority), "low-priority", or "archive". If not specified, shows all chats.',
|
|
44
|
+
enum: ['primary', 'low-priority', 'archive'],
|
|
45
|
+
},
|
|
46
|
+
includeMuted: {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description:
|
|
49
|
+
'Include chats marked as Muted by the user, which are usually less important. Default: true. Set to false if the user wants a more refined search.',
|
|
50
|
+
},
|
|
51
|
+
lastActivityAfter: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
description:
|
|
54
|
+
'Provide an ISO datetime string to only retrieve chats with last activity after this time',
|
|
55
|
+
format: 'date-time',
|
|
56
|
+
},
|
|
57
|
+
lastActivityBefore: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
description:
|
|
60
|
+
'Provide an ISO datetime string to only retrieve chats with last activity before this time',
|
|
61
|
+
format: 'date-time',
|
|
62
|
+
},
|
|
63
|
+
limit: {
|
|
64
|
+
type: 'integer',
|
|
65
|
+
description: 'Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50',
|
|
66
|
+
},
|
|
67
|
+
participantQuery: {
|
|
68
|
+
type: 'string',
|
|
69
|
+
description:
|
|
70
|
+
'Search string to filter chats by participant names. When multiple words provided, ALL words must match. Searches in username, displayName, and fullName fields.',
|
|
71
|
+
},
|
|
72
|
+
query: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
description:
|
|
75
|
+
'Search string to filter chats by title. When multiple words provided, ALL words must match. Matches are case-insensitive substrings.',
|
|
76
|
+
},
|
|
77
|
+
type: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
description:
|
|
80
|
+
'Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, "channel" for channels, or "any" to get all types',
|
|
81
|
+
enum: ['single', 'group', 'channel', 'any'],
|
|
82
|
+
},
|
|
83
|
+
unreadOnly: {
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
description: 'Set to true to only retrieve chats that have unread messages',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
required: [],
|
|
89
|
+
},
|
|
90
|
+
annotations: {
|
|
91
|
+
readOnlyHint: true,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const handler = async (client: BeeperDesktop, args: Record<string, unknown> | undefined) => {
|
|
96
|
+
const body = args as any;
|
|
97
|
+
const response = await client.chats.search(body).asResponse();
|
|
98
|
+
return asTextContentResult(await response.json());
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default { metadata, tool, handler };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
import { Metadata, Endpoint, HandlerFunction } from './types';
|
|
4
|
+
|
|
5
|
+
export { Metadata, Endpoint, HandlerFunction };
|
|
6
|
+
|
|
7
|
+
import get_accounts from './accounts/get-accounts';
|
|
8
|
+
import open_app from './app/open-app';
|
|
9
|
+
import archive_chat from './chats/archive-chat';
|
|
10
|
+
import get_chat from './chats/get-chat';
|
|
11
|
+
import search_chats from './chats/search-chats';
|
|
12
|
+
import get_attachment from './messages/get-attachment';
|
|
13
|
+
import search_messages from './messages/search-messages';
|
|
14
|
+
import send_message from './messages/send-message';
|
|
15
|
+
import clear_chat_reminder from './reminders/clear-chat-reminder';
|
|
16
|
+
import set_chat_reminder from './reminders/set-chat-reminder';
|
|
17
|
+
|
|
18
|
+
export const endpoints: Endpoint[] = [];
|
|
19
|
+
|
|
20
|
+
function addEndpoint(endpoint: Endpoint) {
|
|
21
|
+
endpoints.push(endpoint);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
addEndpoint(get_accounts);
|
|
25
|
+
addEndpoint(open_app);
|
|
26
|
+
addEndpoint(archive_chat);
|
|
27
|
+
addEndpoint(get_chat);
|
|
28
|
+
addEndpoint(search_chats);
|
|
29
|
+
addEndpoint(get_attachment);
|
|
30
|
+
addEndpoint(search_messages);
|
|
31
|
+
addEndpoint(send_message);
|
|
32
|
+
addEndpoint(clear_chat_reminder);
|
|
33
|
+
addEndpoint(set_chat_reminder);
|
|
34
|
+
|
|
35
|
+
export type Filter = {
|
|
36
|
+
type: 'resource' | 'operation' | 'tag' | 'tool';
|
|
37
|
+
op: 'include' | 'exclude';
|
|
38
|
+
value: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function query(filters: Filter[], endpoints: Endpoint[]): Endpoint[] {
|
|
42
|
+
const allExcludes = filters.length > 0 && filters.every((filter) => filter.op === 'exclude');
|
|
43
|
+
const unmatchedFilters = new Set(filters);
|
|
44
|
+
|
|
45
|
+
const filtered = endpoints.filter((endpoint: Endpoint) => {
|
|
46
|
+
let included = false || allExcludes;
|
|
47
|
+
|
|
48
|
+
for (const filter of filters) {
|
|
49
|
+
if (match(filter, endpoint)) {
|
|
50
|
+
unmatchedFilters.delete(filter);
|
|
51
|
+
included = filter.op === 'include';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return included;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Check if any filters didn't match
|
|
59
|
+
const unmatched = Array.from(unmatchedFilters).filter((f) => f.type === 'tool' || f.type === 'resource');
|
|
60
|
+
if (unmatched.length > 0) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`The following filters did not match any endpoints: ${unmatched
|
|
63
|
+
.map((f) => `${f.type}=${f.value}`)
|
|
64
|
+
.join(', ')}`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return filtered;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function match({ type, value }: Filter, endpoint: Endpoint): boolean {
|
|
72
|
+
switch (type) {
|
|
73
|
+
case 'resource': {
|
|
74
|
+
const regexStr = '^' + normalizeResource(value).replace(/\*/g, '.*') + '$';
|
|
75
|
+
const regex = new RegExp(regexStr);
|
|
76
|
+
return regex.test(normalizeResource(endpoint.metadata.resource));
|
|
77
|
+
}
|
|
78
|
+
case 'operation':
|
|
79
|
+
return endpoint.metadata.operation === value;
|
|
80
|
+
case 'tag':
|
|
81
|
+
return endpoint.metadata.tags.includes(value);
|
|
82
|
+
case 'tool':
|
|
83
|
+
return endpoint.tool.name === value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function normalizeResource(resource: string): string {
|
|
88
|
+
return resource.toLowerCase().replace(/[^a-z.*\-_]*/g, '');
|
|
89
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
|
|
3
|
+
import { Metadata, asTextContentResult } from '@beeper/desktop-mcp/tools/types';
|
|
4
|
+
|
|
5
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import BeeperDesktop from '@beeper/desktop-api';
|
|
7
|
+
|
|
8
|
+
export const metadata: Metadata = {
|
|
9
|
+
resource: 'messages',
|
|
10
|
+
operation: 'write',
|
|
11
|
+
tags: ['messages'],
|
|
12
|
+
httpMethod: 'post',
|
|
13
|
+
httpPath: '/v0/get-attachment',
|
|
14
|
+
operationId: 'get_attachment',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const tool: Tool = {
|
|
18
|
+
name: 'get_attachment',
|
|
19
|
+
description: 'Download a message attachment and return the local file path.',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
chatID: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'Unique identifier of the chat (supports both chatID and localChatID).',
|
|
26
|
+
},
|
|
27
|
+
messageID: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'The message ID (eventID) containing the attachment.',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
required: ['chatID', 'messageID'],
|
|
33
|
+
},
|
|
34
|
+
annotations: {},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const handler = async (client: BeeperDesktop, args: Record<string, unknown> | undefined) => {
|
|
38
|
+
const body = args as any;
|
|
39
|
+
return asTextContentResult(await client.messages.getAttachment(body));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default { metadata, tool, handler };
|