@botuyo/mcp 0.3.13 → 0.3.21
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 +135 -30
- package/dist/__tests__/client.spec.d.ts +5 -0
- package/dist/__tests__/client.spec.js +139 -0
- package/dist/__tests__/client.spec.js.map +1 -0
- package/dist/client.d.ts +6 -1
- package/dist/client.js +30 -10
- package/dist/client.js.map +1 -1
- package/dist/commands/__tests__/credentials.spec.d.ts +5 -0
- package/dist/commands/__tests__/credentials.spec.js +174 -0
- package/dist/commands/__tests__/credentials.spec.js.map +1 -0
- package/dist/commands/auth.js +34 -50
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/credentials.d.ts +38 -4
- package/dist/commands/credentials.js +80 -12
- package/dist/commands/credentials.js.map +1 -1
- package/dist/commands/login.js +26 -56
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/switch_tenant.js +11 -36
- package/dist/commands/switch_tenant.js.map +1 -1
- package/dist/commands/tenants.js +10 -19
- package/dist/commands/tenants.js.map +1 -1
- package/dist/index.js +88 -11
- package/dist/index.js.map +1 -1
- package/dist/tools/__tests__/configure_avatar.spec.js +2 -3
- package/dist/tools/__tests__/configure_avatar.spec.js.map +1 -1
- package/dist/tools/configure_agent_tool.js +4 -4
- package/dist/tools/configure_avatar.js +2 -3
- package/dist/tools/configure_avatar.js.map +1 -1
- package/dist/tools/example_agent.d.ts +5 -3
- package/dist/tools/example_agent.js +10 -8
- package/dist/tools/example_agent.js.map +1 -1
- package/dist/tools/index.js +3 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/ingest_knowledge_url.d.ts +4 -0
- package/dist/tools/ingest_knowledge_url.js +35 -0
- package/dist/tools/ingest_knowledge_url.js.map +1 -0
- package/dist/tools/switch_tenant.js +1 -1
- package/dist/tools/switch_tenant.js.map +1 -1
- package/package.json +2 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BotUyo
|
|
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
CHANGED
|
@@ -6,39 +6,49 @@ Create and manage BotUyo AI agents directly from your AI coding tools — **no c
|
|
|
6
6
|
|
|
7
7
|
## Quickstart
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The fastest way — one command configures your editor **and** logs you in:
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
```sh
|
|
12
|
+
npx @botuyo/mcp setup
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
It auto-detects your editor (Cursor, VS Code / Antigravity, Claude Desktop), writes the MCP config, and walks you through authentication.
|
|
12
16
|
|
|
13
|
-
###
|
|
17
|
+
### Manual setup
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
**1. Add the BotUyo server to your MCP client config:**
|
|
16
20
|
|
|
17
21
|
```json
|
|
18
22
|
{
|
|
19
23
|
"mcpServers": {
|
|
20
24
|
"botuyo": {
|
|
21
25
|
"command": "npx",
|
|
22
|
-
"args": ["-y", "@botuyo/mcp"]
|
|
23
|
-
"env": {
|
|
24
|
-
"BOTUYO_API_KEY": "pk_live_your_key_here"
|
|
25
|
-
}
|
|
26
|
+
"args": ["-y", "@botuyo/mcp"]
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
```
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
> No API key goes in the config — authentication is handled by the `auth`/`login` commands below. Some clients (Cursor, VS Code) use the `servers` key instead of `mcpServers`.
|
|
32
33
|
|
|
33
|
-
|
|
|
34
|
+
| Client | Config file |
|
|
34
35
|
|---|---|
|
|
35
|
-
| **
|
|
36
|
-
| **
|
|
37
|
-
| **
|
|
36
|
+
| **Cursor** | `.cursor/mcp.json` |
|
|
37
|
+
| **VS Code / Antigravity** | `.vscode/mcp.json` |
|
|
38
|
+
| **Claude Desktop** | `~/.config/claude/claude_desktop_config.json` (Windows: `%AppData%\Claude\claude_desktop_config.json`) |
|
|
38
39
|
| **Windsurf** | `~/.codeium/windsurf/mcp_config.json` |
|
|
39
|
-
| **Continue** | `.continue/config.json` |
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
**2. Authenticate once** — saves a token to `~/.botuyo/credentials.json`:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npx @botuyo/mcp auth # browser OAuth (recommended)
|
|
45
|
+
# or
|
|
46
|
+
npx @botuyo/mcp login # email + password in the terminal
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The running MCP server picks up your session automatically — no restart needed. Tokens last 7 days; re-run `auth` or `login` to refresh.
|
|
50
|
+
|
|
51
|
+
### Start building agents
|
|
42
52
|
|
|
43
53
|
Once connected, ask your AI assistant things like:
|
|
44
54
|
|
|
@@ -48,19 +58,98 @@ Once connected, ask your AI assistant things like:
|
|
|
48
58
|
> *"Enable the EscalateToHuman and SearchKnowledgeBase tools on Mar"*
|
|
49
59
|
> *"Publish the agent"*
|
|
50
60
|
|
|
51
|
-
##
|
|
61
|
+
## CLI commands
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npx @botuyo/mcp setup # Configure your editor + authenticate (recommended)
|
|
65
|
+
npx @botuyo/mcp auth # Login via browser (OAuth)
|
|
66
|
+
npx @botuyo/mcp login # Login via email + password
|
|
67
|
+
npx @botuyo/mcp tenants # List your tenants
|
|
68
|
+
npx @botuyo/mcp switch-tenant # Switch the active tenant
|
|
69
|
+
npx @botuyo/mcp whoami # Show the current session
|
|
70
|
+
npx @botuyo/mcp logout # Clear stored credentials
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The server resolves your JWT from `BOTUYO_TOKEN`, falling back to `~/.botuyo/credentials.json`. The backend URL defaults to `https://api.botuyo.com` (override with `BOTUYO_API_URL`).
|
|
74
|
+
|
|
75
|
+
## Available tools
|
|
76
|
+
|
|
77
|
+
The server exposes **30 tools**. Read tools (`list_*`, `get_*`, `export_*`) need `viewer+`; write/publish tools need `developer+` (see [Roles](#roles)).
|
|
78
|
+
|
|
79
|
+
### Agents
|
|
80
|
+
|
|
81
|
+
| Tool | Description |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `list_agents` | List all agents in the tenant |
|
|
84
|
+
| `get_agent` | Get an agent's full config (identity, stages, enabled tools) |
|
|
85
|
+
| `get_agent_status` | Channel connection status + admin link to connect missing channels |
|
|
86
|
+
| `create_agent` | Create a new agent |
|
|
87
|
+
| `update_agent` | Update identity (tone, language, objective, custom instructions) |
|
|
88
|
+
| `delete_agent` | Soft-delete an agent (irreversible; requires explicit confirmation) |
|
|
89
|
+
| `publish_agent` | Publish or unpublish an agent (live vs draft) |
|
|
90
|
+
| `example_agent` | Return a fully documented example agent config (read-only reference) |
|
|
91
|
+
|
|
92
|
+
### Conversation flow
|
|
93
|
+
|
|
94
|
+
| Tool | Description |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `upsert_stage` | Create or update a named stage in the agent's conversation graph |
|
|
97
|
+
|
|
98
|
+
### Tools & capabilities
|
|
99
|
+
|
|
100
|
+
| Tool | Description |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `list_available_tools` | List tools available to your tenant (core + custom) |
|
|
103
|
+
| `update_enabled_tools` | Enable/disable tools on an agent |
|
|
104
|
+
| `get_tools_catalog` | Full tool catalog with metadata (configurable, multi-instance, schema, required integrations) |
|
|
105
|
+
| `configure_agent_tool` | Create/update a tool's config on an agent (single or multi-instance) |
|
|
106
|
+
| `list_tool_configs` | List an agent's tool configs, grouped |
|
|
107
|
+
| `get_tool_config` | View the full config of a specific tool on an agent |
|
|
108
|
+
| `remove_tool_config` | Remove a tool's configuration |
|
|
109
|
+
|
|
110
|
+
### Knowledge base
|
|
111
|
+
|
|
112
|
+
| Tool | Description |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `list_knowledge_documents` | List knowledge base documents |
|
|
115
|
+
| `ingest_knowledge_url` | Ingest a URL into the knowledge base |
|
|
116
|
+
| `associate_knowledge_to_agent` | Link knowledge document IDs to an agent |
|
|
117
|
+
| `delete_knowledge_document` | Delete a knowledge document and all its chunks |
|
|
118
|
+
|
|
119
|
+
### Templates
|
|
120
|
+
|
|
121
|
+
| Tool | Description |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `list_templates` | List agent templates by industry |
|
|
124
|
+
| `create_from_template` | Create a new agent from a template |
|
|
125
|
+
|
|
126
|
+
### Import / export
|
|
127
|
+
|
|
128
|
+
| Tool | Description |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `export_agent_json` | Export an agent's full config as editable JSON |
|
|
131
|
+
| `import_agent_json` | Replace an agent's full config from JSON (full overwrite) |
|
|
132
|
+
|
|
133
|
+
### Avatar & media
|
|
134
|
+
|
|
135
|
+
| Tool | Description |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `list_avatars` | List the free 3D avatars in the catalog |
|
|
138
|
+
| `select_avatar` | Set a 3D avatar for an agent (catalog ID or custom .glb/.vrm URL) |
|
|
139
|
+
| `upload_agent_media` | Upload a local image to the CDN as an agent's avatar/logo |
|
|
140
|
+
|
|
141
|
+
### Versioning
|
|
52
142
|
|
|
53
|
-
| Tool | Description |
|
|
54
|
-
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
|
61
|
-
|
|
62
|
-
| `
|
|
63
|
-
| `publish_agent` | Publish or unpublish an agent | developer+ |
|
|
143
|
+
| Tool | Description |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `list_agent_versions` | List an agent's saved version snapshots |
|
|
146
|
+
| `restore_agent_version` | Roll back an agent to a previous version |
|
|
147
|
+
|
|
148
|
+
### Account
|
|
149
|
+
|
|
150
|
+
| Tool | Description |
|
|
151
|
+
|---|---|
|
|
152
|
+
| `switch_tenant` | Switch the active tenant for the session |
|
|
64
153
|
|
|
65
154
|
## Roles
|
|
66
155
|
|
|
@@ -80,14 +169,30 @@ Use `get_agent_status` to check which channels are connected. It returns a direc
|
|
|
80
169
|
## Build from source
|
|
81
170
|
|
|
82
171
|
```sh
|
|
83
|
-
|
|
172
|
+
git clone https://github.com/MarcoAR1/botuyo-mcp.git
|
|
173
|
+
cd botuyo-mcp
|
|
84
174
|
npm install
|
|
85
175
|
npm run build
|
|
86
176
|
```
|
|
87
177
|
|
|
88
178
|
## Test with MCP Inspector
|
|
89
179
|
|
|
180
|
+
Authenticate first (`npx @botuyo/mcp login`), then run:
|
|
181
|
+
|
|
90
182
|
```sh
|
|
91
|
-
|
|
92
|
-
BOTUYO_API_KEY=pk_live_... npm run inspect
|
|
183
|
+
npm run inspect
|
|
93
184
|
```
|
|
185
|
+
|
|
186
|
+
## Contributing
|
|
187
|
+
|
|
188
|
+
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
189
|
+
|
|
190
|
+
Please note that this project follows a [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
191
|
+
|
|
192
|
+
## Security
|
|
193
|
+
|
|
194
|
+
To report a vulnerability, see [SECURITY.md](SECURITY.md).
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
[MIT](LICENSE) © BotUyo
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BotuyoApiClient — Unit tests
|
|
3
|
+
* Tests for error handling, 401 detection, ApiError class
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
+
import { BotuyoApiClient, ApiError } from '../client.js';
|
|
7
|
+
// Mock global fetch
|
|
8
|
+
function mockFetch(status, body, ok) {
|
|
9
|
+
const fn = vi.fn().mockResolvedValue({
|
|
10
|
+
status,
|
|
11
|
+
ok: ok ?? (status >= 200 && status < 300),
|
|
12
|
+
text: async () => JSON.stringify(body),
|
|
13
|
+
json: async () => body
|
|
14
|
+
});
|
|
15
|
+
vi.stubGlobal('fetch', fn);
|
|
16
|
+
return fn;
|
|
17
|
+
}
|
|
18
|
+
describe('BotuyoApiClient', () => {
|
|
19
|
+
let client;
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
vi.restoreAllMocks();
|
|
22
|
+
client = new BotuyoApiClient({ apiUrl: 'http://localhost:8080', token: 'test-token' });
|
|
23
|
+
});
|
|
24
|
+
// ── ApiError class ──────────────────────────────────────────────────
|
|
25
|
+
describe('ApiError', () => {
|
|
26
|
+
it('is an instance of Error', () => {
|
|
27
|
+
const err = new ApiError('test', 401);
|
|
28
|
+
expect(err).toBeInstanceOf(Error);
|
|
29
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
30
|
+
});
|
|
31
|
+
it('stores the HTTP status code', () => {
|
|
32
|
+
const err = new ApiError('Unauthorized', 401);
|
|
33
|
+
expect(err.status).toBe(401);
|
|
34
|
+
expect(err.message).toBe('Unauthorized');
|
|
35
|
+
});
|
|
36
|
+
it('has a name of ApiError', () => {
|
|
37
|
+
const err = new ApiError('test', 500);
|
|
38
|
+
expect(err.name).toBe('ApiError');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
// ── handleResponse / 401 detection ──────────────────────────────────
|
|
42
|
+
describe('401 detection', () => {
|
|
43
|
+
it('throws ApiError with status 401 on unauthorized response', async () => {
|
|
44
|
+
mockFetch(401, { success: false, error: 'Invalid or expired token' });
|
|
45
|
+
try {
|
|
46
|
+
await client.get('/api/v1/mcp/agents');
|
|
47
|
+
expect.fail('should have thrown');
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
51
|
+
expect(err.status).toBe(401);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
it('throws ApiError with status 403 on forbidden response', async () => {
|
|
55
|
+
mockFetch(403, { success: false, error: 'Forbidden' });
|
|
56
|
+
try {
|
|
57
|
+
await client.get('/api/v1/mcp/agents');
|
|
58
|
+
expect.fail('should have thrown');
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
62
|
+
expect(err.status).toBe(403);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
it('throws ApiError with status 500 on server error', async () => {
|
|
66
|
+
mockFetch(500, { success: false, error: 'Internal error' });
|
|
67
|
+
try {
|
|
68
|
+
await client.get('/api/v1/mcp/agents');
|
|
69
|
+
expect.fail('should have thrown');
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
73
|
+
expect(err.status).toBe(500);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
it('does NOT throw on successful 200 responses', async () => {
|
|
77
|
+
mockFetch(200, { success: true, data: { agents: [] } });
|
|
78
|
+
const result = await client.get('/api/v1/mcp/agents');
|
|
79
|
+
expect(result.success).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
// ── verify() ────────────────────────────────────────────────────────
|
|
83
|
+
describe('verify', () => {
|
|
84
|
+
it('returns AuthInfo on successful /api/auth/me', async () => {
|
|
85
|
+
mockFetch(200, {
|
|
86
|
+
success: true,
|
|
87
|
+
data: {
|
|
88
|
+
user: {
|
|
89
|
+
email: 'test@example.com',
|
|
90
|
+
tenantIds: ['t1'],
|
|
91
|
+
roles: [{ tenantId: 't1', role: 'owner' }]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const info = await client.verify();
|
|
96
|
+
expect(info.email).toBe('test@example.com');
|
|
97
|
+
expect(info.tenantId).toBe('t1');
|
|
98
|
+
expect(info.role).toBe('owner');
|
|
99
|
+
});
|
|
100
|
+
it('throws on 401 from /api/auth/me', async () => {
|
|
101
|
+
mockFetch(401, { success: false, error: 'Token expired' });
|
|
102
|
+
await expect(client.verify()).rejects.toThrow();
|
|
103
|
+
});
|
|
104
|
+
it('caches authInfo after first successful call', async () => {
|
|
105
|
+
const fetchFn = mockFetch(200, {
|
|
106
|
+
success: true,
|
|
107
|
+
data: {
|
|
108
|
+
user: {
|
|
109
|
+
email: 'test@example.com',
|
|
110
|
+
tenantIds: ['t1'],
|
|
111
|
+
roles: [{ tenantId: 't1', role: 'owner' }]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
await client.verify();
|
|
116
|
+
await client.verify();
|
|
117
|
+
expect(fetchFn).toHaveBeenCalledTimes(1);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
// ── Non-JSON responses ──────────────────────────────────────────────
|
|
121
|
+
describe('non-JSON responses', () => {
|
|
122
|
+
it('throws ApiError with status code when response is not JSON', async () => {
|
|
123
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
|
|
124
|
+
status: 502,
|
|
125
|
+
ok: false,
|
|
126
|
+
text: async () => '<html>Bad Gateway</html>'
|
|
127
|
+
}));
|
|
128
|
+
try {
|
|
129
|
+
await client.get('/api/v1/mcp/agents');
|
|
130
|
+
expect.fail('should have thrown');
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
expect(err).toBeInstanceOf(ApiError);
|
|
134
|
+
expect(err.status).toBe(502);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=client.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.spec.js","sourceRoot":"","sources":["../../src/__tests__/client.spec.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* Uses a JWT token directly (obtained via `npx @botuyo/mcp auth` or `npx @botuyo/mcp login`).
|
|
6
6
|
* Requires Node 18+ (native fetch).
|
|
7
7
|
*/
|
|
8
|
+
export declare class ApiError extends Error {
|
|
9
|
+
readonly status: number;
|
|
10
|
+
constructor(message: string, status: number);
|
|
11
|
+
}
|
|
8
12
|
export interface BotuyoClientConfig {
|
|
9
13
|
apiUrl: string;
|
|
10
14
|
token: string;
|
|
@@ -18,11 +22,12 @@ export interface AuthInfo {
|
|
|
18
22
|
export declare class BotuyoApiClient {
|
|
19
23
|
private config;
|
|
20
24
|
private authInfo;
|
|
25
|
+
private activeTenantId;
|
|
21
26
|
constructor(config: BotuyoClientConfig);
|
|
22
27
|
/** Get the current JWT token */
|
|
23
28
|
getToken(): string;
|
|
24
29
|
/** Hot-swap the JWT token (used by switch_tenant) */
|
|
25
|
-
setToken(token: string): void;
|
|
30
|
+
setToken(token: string, tenantId?: string): void;
|
|
26
31
|
/** Verify the stored JWT is still valid by calling GET /api/auth/me */
|
|
27
32
|
verify(): Promise<AuthInfo>;
|
|
28
33
|
/** Make an authenticated GET request */
|
package/dist/client.js
CHANGED
|
@@ -5,9 +5,18 @@
|
|
|
5
5
|
* Uses a JWT token directly (obtained via `npx @botuyo/mcp auth` or `npx @botuyo/mcp login`).
|
|
6
6
|
* Requires Node 18+ (native fetch).
|
|
7
7
|
*/
|
|
8
|
+
export class ApiError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
constructor(message, status) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'ApiError';
|
|
13
|
+
this.status = status;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
8
16
|
export class BotuyoApiClient {
|
|
9
17
|
config;
|
|
10
18
|
authInfo = null;
|
|
19
|
+
activeTenantId = null; // Track tenant set by switch_tenant
|
|
11
20
|
constructor(config) {
|
|
12
21
|
this.config = config;
|
|
13
22
|
}
|
|
@@ -16,9 +25,11 @@ export class BotuyoApiClient {
|
|
|
16
25
|
return this.config.token;
|
|
17
26
|
}
|
|
18
27
|
/** Hot-swap the JWT token (used by switch_tenant) */
|
|
19
|
-
setToken(token) {
|
|
28
|
+
setToken(token, tenantId) {
|
|
20
29
|
this.config = { ...this.config, token };
|
|
21
30
|
this.authInfo = null; // reset cached auth info
|
|
31
|
+
if (tenantId)
|
|
32
|
+
this.activeTenantId = tenantId;
|
|
22
33
|
}
|
|
23
34
|
/** Verify the stored JWT is still valid by calling GET /api/auth/me */
|
|
24
35
|
async verify() {
|
|
@@ -32,10 +43,12 @@ export class BotuyoApiClient {
|
|
|
32
43
|
throw new Error(`Session expired or invalid: ${body.error || 'Unknown error'}. Run: npx @botuyo/mcp auth (browser) or npx @botuyo/mcp login (terminal)`);
|
|
33
44
|
}
|
|
34
45
|
const user = body.data.user;
|
|
46
|
+
// Use activeTenantId (from switch_tenant) if set, otherwise fall back to first tenant
|
|
47
|
+
const resolvedTenantId = this.activeTenantId || user.tenantIds?.[0] || '';
|
|
35
48
|
this.authInfo = {
|
|
36
|
-
tenantId:
|
|
49
|
+
tenantId: resolvedTenantId,
|
|
37
50
|
tenantName: '', // Will be enriched from credentials
|
|
38
|
-
role: user.roles?.[0]?.role || 'member',
|
|
51
|
+
role: user.roles?.find((r) => r.tenantId === resolvedTenantId)?.role || user.roles?.[0]?.role || 'member',
|
|
39
52
|
email: user.email
|
|
40
53
|
};
|
|
41
54
|
return this.authInfo;
|
|
@@ -82,10 +95,17 @@ export class BotuyoApiClient {
|
|
|
82
95
|
return this.handleResponse(res);
|
|
83
96
|
}
|
|
84
97
|
async handleResponse(res) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
98
|
+
const text = await res.text();
|
|
99
|
+
let json;
|
|
100
|
+
try {
|
|
101
|
+
json = JSON.parse(text);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
throw new ApiError(`HTTP ${res.status}: ${text.slice(0, 200)}`, res.status);
|
|
105
|
+
}
|
|
106
|
+
if (!res.ok) {
|
|
107
|
+
const msg = json.error || `HTTP ${res.status}`;
|
|
108
|
+
throw new ApiError(msg, res.status);
|
|
89
109
|
}
|
|
90
110
|
return json;
|
|
91
111
|
}
|
|
@@ -117,14 +137,14 @@ export class BotuyoApiClient {
|
|
|
117
137
|
try {
|
|
118
138
|
const json = JSON.parse(text);
|
|
119
139
|
if (!res.ok && !json.success) {
|
|
120
|
-
throw new
|
|
140
|
+
throw new ApiError(json.error || `HTTP ${res.status}`, res.status);
|
|
121
141
|
}
|
|
122
142
|
return json;
|
|
123
143
|
}
|
|
124
144
|
catch (e) {
|
|
125
|
-
if (e instanceof
|
|
145
|
+
if (e instanceof ApiError)
|
|
126
146
|
throw e;
|
|
127
|
-
throw new
|
|
147
|
+
throw new ApiError(`HTTP ${res.status}: ${text.slice(0, 200)}`, res.status);
|
|
128
148
|
}
|
|
129
149
|
}
|
|
130
150
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|