@besales/mcp 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/LICENSE +21 -0
- package/README.md +127 -0
- package/bin/besales-mcp.js +10 -0
- package/dist/auth/oauth-client.d.ts +32 -0
- package/dist/auth/oauth-client.js +180 -0
- package/dist/auth/oauth-client.js.map +1 -0
- package/dist/auth/token-storage.d.ts +7 -0
- package/dist/auth/token-storage.js +17 -0
- package/dist/auth/token-storage.js.map +1 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.js +70 -0
- package/dist/cli.js.map +1 -0
- package/dist/http/api-client.d.ts +51 -0
- package/dist/http/api-client.js +115 -0
- package/dist/http/api-client.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/package-metadata.d.ts +1 -0
- package/dist/package-metadata.js +6 -0
- package/dist/package-metadata.js.map +1 -0
- package/dist/resources/concepts/external-execution.md +22 -0
- package/dist/resources/concepts/handoff.md +16 -0
- package/dist/resources/concepts/icp.md +16 -0
- package/dist/resources/concepts/sandbox.md +17 -0
- package/dist/resources/concepts/triggers.md +16 -0
- package/dist/resources/registry.d.ts +5 -0
- package/dist/resources/registry.js +33 -0
- package/dist/resources/registry.js.map +1 -0
- package/dist/schemas/mcp-tools.json +1192 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.js +74 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/contracts.d.ts +22 -0
- package/dist/tools/contracts.js +24 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/definitions.d.ts +307 -0
- package/dist/tools/definitions.js +859 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/registry.d.ts +11 -0
- package/dist/tools/registry.js +52 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/result.d.ts +4 -0
- package/dist/tools/result.js +78 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/types/api-contract.gen.d.ts +6975 -0
- package/dist/types/api-contract.gen.js +6 -0
- package/dist/types/api-contract.gen.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +13 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mask.d.ts +1 -0
- package/dist/utils/mask.js +7 -0
- package/dist/utils/mask.js.map +1 -0
- package/docs/host-setup.md +256 -0
- package/package.json +81 -0
- package/scripts/install-claude-desktop.js +77 -0
- package/scripts/mock-api-server.js +56 -0
- package/scripts/mock-credentials.js +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BeSales
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# @besales/mcp
|
|
2
|
+
|
|
3
|
+
Model Context Protocol server for Animaly / Besales.
|
|
4
|
+
|
|
5
|
+
Status: public npm package candidate.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Production users can run the MCP server with `npx`:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx -y @besales/mcp connect
|
|
13
|
+
npx -y @besales/mcp status
|
|
14
|
+
npx -y @besales/mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Development
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
yarn install
|
|
21
|
+
yarn types:gen:api
|
|
22
|
+
yarn types:gen:mcp
|
|
23
|
+
yarn build
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The generated files in `src/types/` and `src/schemas/` are committed because
|
|
27
|
+
the source contracts live outside this independent repository.
|
|
28
|
+
|
|
29
|
+
Run a lightweight local mock API for MCP Inspector tool-call smoke tests:
|
|
30
|
+
|
|
31
|
+
Terminal 1:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
yarn dev:mock
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Terminal 2:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
yarn dev:mock:seed
|
|
41
|
+
BESALES_API_BASE_URL=http://127.0.0.1:3100/api/v2 node bin/besales-mcp.js
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`yarn dev:mock:seed` and `yarn dev:mock:clear` use the same keytar entries as
|
|
45
|
+
real `besales-mcp connect` credentials. They can overwrite or clear a local real
|
|
46
|
+
connection for the current macOS user.
|
|
47
|
+
|
|
48
|
+
The mock server only verifies request wiring. Live tool E2E depends on the
|
|
49
|
+
matching `ai-aniomaly` `/api/v2/*` endpoints.
|
|
50
|
+
Remove seeded mock credentials after smoke testing:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
yarn dev:mock:clear
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## CLI
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
node bin/besales-mcp.js connect
|
|
60
|
+
node bin/besales-mcp.js status
|
|
61
|
+
node bin/besales-mcp.js disconnect
|
|
62
|
+
node bin/besales-mcp.js
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`BESALES_API_BASE_URL` defaults to `https://app.besales.ai/api/v2`. For local
|
|
66
|
+
development, set it to `http://localhost:3000/api/v2`.
|
|
67
|
+
|
|
68
|
+
Tool calls require stored credentials. Run `node bin/besales-mcp.js connect`
|
|
69
|
+
against a backend that implements `/api/v2/auth/mcp-connect`, or run
|
|
70
|
+
`yarn dev:mock:seed` for mock-only smoke tests.
|
|
71
|
+
|
|
72
|
+
For production users, do not set `BESALES_API_BASE_URL`. Run:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx -y @besales/mcp connect
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The browser consent flow stores the selected workspace in the local keychain.
|
|
79
|
+
Workspace-level tools default to that connected workspace, so users should not
|
|
80
|
+
provide `workspace_id` manually. To switch workspace, run `besales-mcp
|
|
81
|
+
disconnect`, switch/create the desired workspace in the web app if needed, then
|
|
82
|
+
run `besales-mcp connect` again.
|
|
83
|
+
|
|
84
|
+
## Resources
|
|
85
|
+
|
|
86
|
+
The package exposes 5 MCP concept resources:
|
|
87
|
+
|
|
88
|
+
- `besales://concepts/icp`
|
|
89
|
+
- `besales://concepts/triggers`
|
|
90
|
+
- `besales://concepts/sandbox`
|
|
91
|
+
- `besales://concepts/handoff`
|
|
92
|
+
- `besales://concepts/external-execution`
|
|
93
|
+
|
|
94
|
+
Inspect them locally:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
yarn dlx @modelcontextprotocol/inspector node bin/besales-mcp.js
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The Inspector should show 31 tools and 5 resources.
|
|
101
|
+
|
|
102
|
+
## Claude Desktop
|
|
103
|
+
|
|
104
|
+
For local development before the package is published, install a Claude Desktop
|
|
105
|
+
config entry with:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
yarn install:claude-desktop
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The installer creates a timestamped backup of the existing config and writes only
|
|
112
|
+
the `mcpServers.besales` entry. It uses the absolute Node executable path because
|
|
113
|
+
GUI apps may not inherit the shell `PATH`.
|
|
114
|
+
|
|
115
|
+
## Host Setup
|
|
116
|
+
|
|
117
|
+
Host-specific local setup and smoke steps for MCP Inspector, Claude Desktop,
|
|
118
|
+
Claude Code, and Codex CLI are documented in
|
|
119
|
+
[docs/host-setup.md](docs/host-setup.md).
|
|
120
|
+
|
|
121
|
+
## Scope
|
|
122
|
+
|
|
123
|
+
- Claude Desktop / Claude Code / Codex call this package through MCP.
|
|
124
|
+
- This package calls Animaly only through `ai-aniomaly` `/api/v2/*`.
|
|
125
|
+
- Direct calls to `prompt-services` are intentionally out of scope.
|
|
126
|
+
|
|
127
|
+
The package exposes 31 active MCP tools from `src/schemas/mcp-tools.json`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const DEFAULT_API_BASE_URL = "https://app.besales.ai/api/v2";
|
|
2
|
+
export declare const OAUTH_CALLBACK_HOST = "127.0.0.1";
|
|
3
|
+
export declare const OAUTH_CALLBACK_PATH = "/oauth-callback";
|
|
4
|
+
export declare const OAUTH_SCOPE = "mcp:* mcp:platform-setup";
|
|
5
|
+
export declare const OAUTH_TIMEOUT_MS: number;
|
|
6
|
+
export interface OAuthConnectResult {
|
|
7
|
+
readonly apiKey: string;
|
|
8
|
+
readonly workspaceId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface OauthClientOptions {
|
|
11
|
+
readonly apiBaseUrl?: string;
|
|
12
|
+
readonly openUrl?: (url: string) => Promise<unknown> | unknown;
|
|
13
|
+
readonly timeoutMs?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function generateCodeVerifier(): string;
|
|
16
|
+
export declare function createCodeChallenge(codeVerifier: string): string;
|
|
17
|
+
export declare function generateState(): string;
|
|
18
|
+
export declare function normalizeApiBaseUrl(apiBaseUrl?: string): string;
|
|
19
|
+
export declare function createAuthorizationUrl(input: {
|
|
20
|
+
readonly apiBaseUrl?: string;
|
|
21
|
+
readonly state: string;
|
|
22
|
+
readonly redirectUri: string;
|
|
23
|
+
readonly codeChallenge: string;
|
|
24
|
+
}): URL;
|
|
25
|
+
export declare class OauthClient {
|
|
26
|
+
private readonly apiBaseUrl;
|
|
27
|
+
private readonly openUrl;
|
|
28
|
+
private readonly timeoutMs;
|
|
29
|
+
constructor(options?: OauthClientOptions);
|
|
30
|
+
connect(): Promise<OAuthConnectResult>;
|
|
31
|
+
private startCallbackServer;
|
|
32
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { createServer } from 'node:http';
|
|
3
|
+
import open from 'open';
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
export const DEFAULT_API_BASE_URL = 'https://app.besales.ai/api/v2';
|
|
6
|
+
export const OAUTH_CALLBACK_HOST = '127.0.0.1';
|
|
7
|
+
export const OAUTH_CALLBACK_PATH = '/oauth-callback';
|
|
8
|
+
export const OAUTH_SCOPE = 'mcp:* mcp:platform-setup';
|
|
9
|
+
export const OAUTH_TIMEOUT_MS = 5 * 60 * 1000;
|
|
10
|
+
export function generateCodeVerifier() {
|
|
11
|
+
return randomBytes(32).toString('base64url');
|
|
12
|
+
}
|
|
13
|
+
export function createCodeChallenge(codeVerifier) {
|
|
14
|
+
return createHash('sha256').update(codeVerifier).digest('base64url');
|
|
15
|
+
}
|
|
16
|
+
export function generateState() {
|
|
17
|
+
return randomBytes(16).toString('hex');
|
|
18
|
+
}
|
|
19
|
+
export function normalizeApiBaseUrl(apiBaseUrl) {
|
|
20
|
+
return (apiBaseUrl ?? process.env.BESALES_API_BASE_URL ?? DEFAULT_API_BASE_URL).replace(/\/+$/, '');
|
|
21
|
+
}
|
|
22
|
+
export function createAuthorizationUrl(input) {
|
|
23
|
+
const url = new URL(`${normalizeApiBaseUrl(input.apiBaseUrl)}/auth/mcp-connect`);
|
|
24
|
+
url.searchParams.set('state', input.state);
|
|
25
|
+
url.searchParams.set('redirect_uri', input.redirectUri);
|
|
26
|
+
url.searchParams.set('code_challenge', input.codeChallenge);
|
|
27
|
+
url.searchParams.set('code_challenge_method', 'S256');
|
|
28
|
+
url.searchParams.set('scope', OAUTH_SCOPE);
|
|
29
|
+
return url;
|
|
30
|
+
}
|
|
31
|
+
export class OauthClient {
|
|
32
|
+
apiBaseUrl;
|
|
33
|
+
openUrl;
|
|
34
|
+
timeoutMs;
|
|
35
|
+
constructor(options = {}) {
|
|
36
|
+
this.apiBaseUrl = normalizeApiBaseUrl(options.apiBaseUrl);
|
|
37
|
+
this.openUrl = options.openUrl ?? ((url) => open(url));
|
|
38
|
+
this.timeoutMs = options.timeoutMs ?? OAUTH_TIMEOUT_MS;
|
|
39
|
+
}
|
|
40
|
+
async connect() {
|
|
41
|
+
const codeVerifier = generateCodeVerifier();
|
|
42
|
+
const codeChallenge = createCodeChallenge(codeVerifier);
|
|
43
|
+
const state = generateState();
|
|
44
|
+
const callbackServer = await this.startCallbackServer({ expectedState: state });
|
|
45
|
+
const redirectUri = `http://${OAUTH_CALLBACK_HOST}:${callbackServer.port}${OAUTH_CALLBACK_PATH}`;
|
|
46
|
+
const authorizationUrl = createAuthorizationUrl({
|
|
47
|
+
apiBaseUrl: this.apiBaseUrl,
|
|
48
|
+
state,
|
|
49
|
+
redirectUri,
|
|
50
|
+
codeChallenge,
|
|
51
|
+
});
|
|
52
|
+
const callbackResult = callbackServer.result;
|
|
53
|
+
callbackResult.catch(() => undefined);
|
|
54
|
+
try {
|
|
55
|
+
await this.openUrl(authorizationUrl.toString());
|
|
56
|
+
return await callbackResult;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
await callbackServer.close();
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async startCallbackServer(input) {
|
|
64
|
+
const server = createServer();
|
|
65
|
+
let settled = false;
|
|
66
|
+
let timeout;
|
|
67
|
+
let closePromise = null;
|
|
68
|
+
const close = async () => {
|
|
69
|
+
if (closePromise) {
|
|
70
|
+
return closePromise;
|
|
71
|
+
}
|
|
72
|
+
if (timeout) {
|
|
73
|
+
clearTimeout(timeout);
|
|
74
|
+
timeout = undefined;
|
|
75
|
+
}
|
|
76
|
+
closePromise = new Promise((resolve) => {
|
|
77
|
+
if (!server.listening) {
|
|
78
|
+
resolve();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
server.closeAllConnections();
|
|
82
|
+
server.close(() => resolve());
|
|
83
|
+
});
|
|
84
|
+
return closePromise;
|
|
85
|
+
};
|
|
86
|
+
const result = new Promise((resolve, reject) => {
|
|
87
|
+
const settle = (outcome, value) => {
|
|
88
|
+
if (settled) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
settled = true;
|
|
92
|
+
if (outcome === 'resolve') {
|
|
93
|
+
resolve(value);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
reject(value);
|
|
97
|
+
}
|
|
98
|
+
void close();
|
|
99
|
+
};
|
|
100
|
+
const rejectCallback = (statusCode, responseMessage, errorMessage, response) => {
|
|
101
|
+
response.writeHead(statusCode, {
|
|
102
|
+
'Connection': 'close',
|
|
103
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
104
|
+
});
|
|
105
|
+
response.end(responseMessage);
|
|
106
|
+
logger.warn({ errorMessage }, 'OAuth callback rejected');
|
|
107
|
+
settle('reject', new Error(errorMessage));
|
|
108
|
+
};
|
|
109
|
+
server.on('request', (request, response) => {
|
|
110
|
+
if (settled) {
|
|
111
|
+
response.writeHead(410, {
|
|
112
|
+
'Connection': 'close',
|
|
113
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
114
|
+
});
|
|
115
|
+
response.end('OAuth flow already completed');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (request.method !== 'GET') {
|
|
119
|
+
rejectCallback(405, 'Method not allowed', 'OAuth callback method must be GET', response);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const callbackAddress = server.address();
|
|
123
|
+
const requestUrl = new URL(request.url ?? '/', `http://${OAUTH_CALLBACK_HOST}:${callbackAddress?.port ?? 0}`);
|
|
124
|
+
if (requestUrl.pathname !== OAUTH_CALLBACK_PATH) {
|
|
125
|
+
rejectCallback(404, 'Not found', 'OAuth callback path mismatch', response);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const receivedState = requestUrl.searchParams.get('state');
|
|
129
|
+
if (receivedState !== input.expectedState) {
|
|
130
|
+
rejectCallback(400, 'Invalid state parameter', 'OAuth state mismatch', response);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const apiKey = requestUrl.searchParams.get('api_key');
|
|
134
|
+
const workspaceId = requestUrl.searchParams.get('workspace_id');
|
|
135
|
+
if (!apiKey || !workspaceId) {
|
|
136
|
+
rejectCallback(400, 'Missing api_key/workspace_id', 'OAuth callback missing required params', response);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
response.writeHead(200, {
|
|
140
|
+
'Connection': 'close',
|
|
141
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
142
|
+
});
|
|
143
|
+
response.end('<html><body><h1>Connected</h1><p>You can close this tab.</p></body></html>');
|
|
144
|
+
settle('resolve', { apiKey, workspaceId });
|
|
145
|
+
});
|
|
146
|
+
server.on('error', (error) => {
|
|
147
|
+
logger.error({ err: error }, 'OAuth callback server error');
|
|
148
|
+
settle('reject', error);
|
|
149
|
+
});
|
|
150
|
+
timeout = setTimeout(() => {
|
|
151
|
+
logger.warn('OAuth flow timeout');
|
|
152
|
+
settle('reject', new Error('OAuth flow timeout (5min)'));
|
|
153
|
+
}, this.timeoutMs);
|
|
154
|
+
});
|
|
155
|
+
await new Promise((resolve, reject) => {
|
|
156
|
+
const onListenError = (error) => {
|
|
157
|
+
server.off('listening', onListening);
|
|
158
|
+
reject(error);
|
|
159
|
+
};
|
|
160
|
+
const onListening = () => {
|
|
161
|
+
server.off('error', onListenError);
|
|
162
|
+
resolve();
|
|
163
|
+
};
|
|
164
|
+
server.once('error', onListenError);
|
|
165
|
+
server.once('listening', onListening);
|
|
166
|
+
server.listen(0, OAUTH_CALLBACK_HOST);
|
|
167
|
+
});
|
|
168
|
+
const address = server.address();
|
|
169
|
+
if (!address || typeof address === 'string') {
|
|
170
|
+
await close();
|
|
171
|
+
throw new Error('OAuth callback server did not expose a TCP port');
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
port: address.port,
|
|
175
|
+
result,
|
|
176
|
+
close,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=oauth-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-client.js","sourceRoot":"","sources":["../../src/auth/oauth-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const TOKEN_STORAGE_SERVICE = "@besales/mcp";
|
|
2
|
+
export type TokenStorageAccount = 'api_key' | 'workspace_id';
|
|
3
|
+
export declare class TokenStorage {
|
|
4
|
+
set(account: TokenStorageAccount, value: string): Promise<void>;
|
|
5
|
+
get(account: TokenStorageAccount): Promise<string | null>;
|
|
6
|
+
clear(): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as keytar from 'keytar';
|
|
2
|
+
export const TOKEN_STORAGE_SERVICE = '@besales/mcp';
|
|
3
|
+
export class TokenStorage {
|
|
4
|
+
async set(account, value) {
|
|
5
|
+
await keytar.setPassword(TOKEN_STORAGE_SERVICE, account, value);
|
|
6
|
+
}
|
|
7
|
+
async get(account) {
|
|
8
|
+
return keytar.getPassword(TOKEN_STORAGE_SERVICE, account);
|
|
9
|
+
}
|
|
10
|
+
async clear() {
|
|
11
|
+
await Promise.all([
|
|
12
|
+
keytar.deletePassword(TOKEN_STORAGE_SERVICE, 'api_key'),
|
|
13
|
+
keytar.deletePassword(TOKEN_STORAGE_SERVICE, 'workspace_id'),
|
|
14
|
+
]);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=token-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-storage.js","sourceRoot":"","sources":["../../src/auth/token-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC;AAGpD,MAAM,OAAO,YAAY;IACvB,KAAK,CAAC,GAAG,CAAC,OAA4B,EAAE,KAAa;QACnD,MAAM,MAAM,CAAC,WAAW,CAAC,qBAAqB,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,OAA4B;QACpC,OAAO,MAAM,CAAC,WAAW,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,MAAM,CAAC,cAAc,CAAC,qBAAqB,EAAE,SAAS,CAAC;YACvD,MAAM,CAAC,cAAc,CAAC,qBAAqB,EAAE,cAAc,CAAC;SAC7D,CAAC,CAAC;IACL,CAAC;CACF"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type OAuthConnectResult } from './auth/oauth-client.js';
|
|
2
|
+
import { type TokenStorageAccount } from './auth/token-storage.js';
|
|
3
|
+
import { startMcpServer } from './server.js';
|
|
4
|
+
export interface CliIo {
|
|
5
|
+
readonly log: (message: string) => void;
|
|
6
|
+
readonly error: (message: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface OAuthConnector {
|
|
9
|
+
connect(): Promise<OAuthConnectResult>;
|
|
10
|
+
}
|
|
11
|
+
export interface CredentialStorage {
|
|
12
|
+
set(account: TokenStorageAccount, value: string): Promise<void>;
|
|
13
|
+
get(account: TokenStorageAccount): Promise<string | null>;
|
|
14
|
+
clear(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export interface CliDeps {
|
|
17
|
+
readonly oauthClient?: OAuthConnector;
|
|
18
|
+
readonly tokenStorage?: CredentialStorage;
|
|
19
|
+
readonly startMcpServer?: typeof startMcpServer;
|
|
20
|
+
}
|
|
21
|
+
export declare function getHelpText(version?: string): string;
|
|
22
|
+
export declare function runCli(argv?: readonly string[], io?: CliIo, deps?: CliDeps): Promise<number>;
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OauthClient } from './auth/oauth-client.js';
|
|
2
|
+
import { TokenStorage } from './auth/token-storage.js';
|
|
3
|
+
import { readPackageVersion } from './package-metadata.js';
|
|
4
|
+
import { startMcpServer } from './server.js';
|
|
5
|
+
import { maskApiKey } from './utils/mask.js';
|
|
6
|
+
const defaultIo = {
|
|
7
|
+
log: (message) => console.log(message),
|
|
8
|
+
error: (message) => console.error(message),
|
|
9
|
+
};
|
|
10
|
+
export function getHelpText(version = readPackageVersion()) {
|
|
11
|
+
return `besales-mcp ${version}
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
besales-mcp Start MCP server
|
|
15
|
+
besales-mcp connect Connect Animaly workspace
|
|
16
|
+
besales-mcp status Show connection status
|
|
17
|
+
besales-mcp disconnect Clear stored credentials
|
|
18
|
+
besales-mcp --help Show help
|
|
19
|
+
besales-mcp --version Show version`;
|
|
20
|
+
}
|
|
21
|
+
export async function runCli(argv = process.argv.slice(2), io = defaultIo, deps = {}) {
|
|
22
|
+
const command = argv[0];
|
|
23
|
+
const oauthClient = deps.oauthClient ?? new OauthClient();
|
|
24
|
+
const tokenStorage = deps.tokenStorage ?? new TokenStorage();
|
|
25
|
+
const runMcpServer = deps.startMcpServer ?? startMcpServer;
|
|
26
|
+
if (command === '--help' || command === '-h') {
|
|
27
|
+
io.log(getHelpText());
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
if (command === '--version' || command === '-v') {
|
|
31
|
+
io.log(readPackageVersion());
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
if (command === 'connect') {
|
|
35
|
+
const { apiKey, workspaceId } = await oauthClient.connect();
|
|
36
|
+
try {
|
|
37
|
+
await tokenStorage.set('workspace_id', workspaceId);
|
|
38
|
+
await tokenStorage.set('api_key', apiKey);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
await tokenStorage.clear();
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
io.log(`Connected to workspace ${workspaceId} (key: ${maskApiKey(apiKey)})`);
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
if (command === 'status') {
|
|
48
|
+
const apiKey = await tokenStorage.get('api_key');
|
|
49
|
+
const workspaceId = await tokenStorage.get('workspace_id');
|
|
50
|
+
if (!apiKey) {
|
|
51
|
+
io.log('Not connected');
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
io.log(`Connected to workspace ${workspaceId ?? 'unknown'} (key: ${maskApiKey(apiKey)})`);
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
if (command === 'disconnect') {
|
|
58
|
+
await tokenStorage.clear();
|
|
59
|
+
io.log('Disconnected');
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
if (command) {
|
|
63
|
+
io.error(`Unknown command: ${command}`);
|
|
64
|
+
io.log(getHelpText());
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
await runMcpServer({ stdio: true });
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type TokenStorageAccount } from '../auth/token-storage.js';
|
|
2
|
+
export declare const API_REQUEST_TIMEOUT_MS = 60000;
|
|
3
|
+
export type ApiMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
4
|
+
export interface CredentialReader {
|
|
5
|
+
get(account: TokenStorageAccount): Promise<string | null>;
|
|
6
|
+
}
|
|
7
|
+
export interface ApiTransportRequest {
|
|
8
|
+
readonly method: ApiMethod;
|
|
9
|
+
readonly url: string;
|
|
10
|
+
readonly data?: unknown;
|
|
11
|
+
readonly headers: Record<string, string>;
|
|
12
|
+
readonly timeout: number;
|
|
13
|
+
}
|
|
14
|
+
export interface ApiTransportResponse<T> {
|
|
15
|
+
readonly status: number;
|
|
16
|
+
readonly data: T;
|
|
17
|
+
}
|
|
18
|
+
export interface ApiTransport {
|
|
19
|
+
request<T = unknown>(request: ApiTransportRequest): Promise<ApiTransportResponse<T>>;
|
|
20
|
+
}
|
|
21
|
+
export interface ApiClientOptions {
|
|
22
|
+
readonly apiBaseUrl?: string;
|
|
23
|
+
readonly tokenStorage?: CredentialReader;
|
|
24
|
+
readonly transport?: ApiTransport;
|
|
25
|
+
readonly timeoutMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ToolApiClient {
|
|
28
|
+
post<T>(path: string, body?: unknown): Promise<T>;
|
|
29
|
+
request<T>(method: ApiMethod, path: string, body?: unknown): Promise<T>;
|
|
30
|
+
getStoredWorkspaceId(): Promise<string | null>;
|
|
31
|
+
}
|
|
32
|
+
export declare class ApiClientError extends Error {
|
|
33
|
+
readonly status?: number | undefined;
|
|
34
|
+
readonly responseMessage?: string | undefined;
|
|
35
|
+
constructor(message: string, status?: number | undefined, responseMessage?: string | undefined);
|
|
36
|
+
}
|
|
37
|
+
export declare class ApiClientNetworkError extends Error {
|
|
38
|
+
constructor(message: string);
|
|
39
|
+
}
|
|
40
|
+
export declare class ApiClient implements ToolApiClient {
|
|
41
|
+
private readonly apiBaseUrl;
|
|
42
|
+
private readonly tokenStorage;
|
|
43
|
+
private readonly transport;
|
|
44
|
+
private readonly timeoutMs;
|
|
45
|
+
constructor(options?: ApiClientOptions);
|
|
46
|
+
post<T>(path: string, body?: unknown): Promise<T>;
|
|
47
|
+
patch<T>(path: string, body?: unknown): Promise<T>;
|
|
48
|
+
getStoredWorkspaceId(): Promise<string | null>;
|
|
49
|
+
request<T>(method: ApiMethod, path: string, body?: unknown): Promise<T>;
|
|
50
|
+
}
|
|
51
|
+
export declare function buildApiUrl(apiBaseUrl: string, path: string): string;
|