@toolplex/client 0.1.1
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 +98 -0
- package/README.md +112 -0
- package/dist/mcp-server/clientContext.d.ts +35 -0
- package/dist/mcp-server/clientContext.js +107 -0
- package/dist/mcp-server/index.d.ts +1 -0
- package/dist/mcp-server/index.js +22 -0
- package/dist/mcp-server/logging/telemetryLogger.d.ts +18 -0
- package/dist/mcp-server/logging/telemetryLogger.js +54 -0
- package/dist/mcp-server/policy/callToolObserver.d.ts +9 -0
- package/dist/mcp-server/policy/callToolObserver.js +25 -0
- package/dist/mcp-server/policy/feedbackPolicy.d.ts +27 -0
- package/dist/mcp-server/policy/feedbackPolicy.js +39 -0
- package/dist/mcp-server/policy/installObserver.d.ts +11 -0
- package/dist/mcp-server/policy/installObserver.js +35 -0
- package/dist/mcp-server/policy/playbookPolicy.d.ts +29 -0
- package/dist/mcp-server/policy/playbookPolicy.js +81 -0
- package/dist/mcp-server/policy/policyEnforcer.d.ts +57 -0
- package/dist/mcp-server/policy/policyEnforcer.js +105 -0
- package/dist/mcp-server/policy/serverPolicy.d.ts +39 -0
- package/dist/mcp-server/policy/serverPolicy.js +61 -0
- package/dist/mcp-server/promptsCache.d.ts +25 -0
- package/dist/mcp-server/promptsCache.js +51 -0
- package/dist/mcp-server/registry.d.ts +34 -0
- package/dist/mcp-server/registry.js +109 -0
- package/dist/mcp-server/serversCache.d.ts +53 -0
- package/dist/mcp-server/serversCache.js +100 -0
- package/dist/mcp-server/staticPrompts.d.ts +6 -0
- package/dist/mcp-server/staticPrompts.js +6 -0
- package/dist/mcp-server/toolDefinitionsCache.d.ts +33 -0
- package/dist/mcp-server/toolDefinitionsCache.js +67 -0
- package/dist/mcp-server/toolHandlers/callToolHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/callToolHandler.js +79 -0
- package/dist/mcp-server/toolHandlers/getServerConfigHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/getServerConfigHandler.js +69 -0
- package/dist/mcp-server/toolHandlers/initHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/initHandler.js +117 -0
- package/dist/mcp-server/toolHandlers/installServerHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/installServerHandler.js +151 -0
- package/dist/mcp-server/toolHandlers/listServersHandler.d.ts +2 -0
- package/dist/mcp-server/toolHandlers/listServersHandler.js +81 -0
- package/dist/mcp-server/toolHandlers/listToolsHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/listToolsHandler.js +112 -0
- package/dist/mcp-server/toolHandlers/logPlaybookUsageHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/logPlaybookUsageHandler.js +65 -0
- package/dist/mcp-server/toolHandlers/lookupEntityHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/lookupEntityHandler.js +112 -0
- package/dist/mcp-server/toolHandlers/savePlaybookHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/savePlaybookHandler.js +65 -0
- package/dist/mcp-server/toolHandlers/searchHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/searchHandler.js +114 -0
- package/dist/mcp-server/toolHandlers/serverManagerUtils.d.ts +2 -0
- package/dist/mcp-server/toolHandlers/serverManagerUtils.js +20 -0
- package/dist/mcp-server/toolHandlers/submitFeedbackHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/submitFeedbackHandler.js +70 -0
- package/dist/mcp-server/toolHandlers/uninstallServerHandler.d.ts +3 -0
- package/dist/mcp-server/toolHandlers/uninstallServerHandler.js +83 -0
- package/dist/mcp-server/toolplexApi/service.d.ts +32 -0
- package/dist/mcp-server/toolplexApi/service.js +222 -0
- package/dist/mcp-server/toolplexApi/types.d.ts +124 -0
- package/dist/mcp-server/toolplexApi/types.js +1 -0
- package/dist/mcp-server/toolplexServer.d.ts +3 -0
- package/dist/mcp-server/toolplexServer.js +249 -0
- package/dist/mcp-server/tools.d.ts +2 -0
- package/dist/mcp-server/tools.js +13 -0
- package/dist/mcp-server/utils/initServerManagers.d.ts +6 -0
- package/dist/mcp-server/utils/initServerManagers.js +31 -0
- package/dist/mcp-server/utils/resultAnnotators.d.ts +23 -0
- package/dist/mcp-server/utils/resultAnnotators.js +50 -0
- package/dist/mcp-server/utils/runtimeCheck.d.ts +4 -0
- package/dist/mcp-server/utils/runtimeCheck.js +30 -0
- package/dist/server-manager/index.d.ts +1 -0
- package/dist/server-manager/index.js +8 -0
- package/dist/server-manager/serverManager.d.ts +37 -0
- package/dist/server-manager/serverManager.js +419 -0
- package/dist/server-manager/stdioServer.d.ts +9 -0
- package/dist/server-manager/stdioServer.js +136 -0
- package/dist/server-manager/stdioTransportProtocol.d.ts +31 -0
- package/dist/server-manager/stdioTransportProtocol.js +67 -0
- package/dist/shared/enhancedPath.d.ts +7 -0
- package/dist/shared/enhancedPath.js +52 -0
- package/dist/shared/fileLogger.d.ts +13 -0
- package/dist/shared/fileLogger.js +66 -0
- package/dist/shared/mcpServerTypes.d.ts +398 -0
- package/dist/shared/mcpServerTypes.js +148 -0
- package/dist/shared/serverManagerTypes.d.ts +179 -0
- package/dist/shared/serverManagerTypes.js +73 -0
- package/dist/shared/stdioServerManagerClient.d.ts +12 -0
- package/dist/shared/stdioServerManagerClient.js +96 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
License text copyright (c) 2025 ToolPlex LLC. All Rights Reserved.
|
|
2
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
3
|
+
|
|
4
|
+
Parameters
|
|
5
|
+
|
|
6
|
+
Licensor: ToolPlex LLC
|
|
7
|
+
Licensed Work: ToolPlex Client, as published in this repository. The Licensed Work is (c) 2025
|
|
8
|
+
ToolPlex LLC.
|
|
9
|
+
Additional Use Grant: You may make production use of the Licensed Work, provided
|
|
10
|
+
your use does not involve offering it or derivative works on a
|
|
11
|
+
hosted or embedded basis to compete with ToolPlex's paid platform
|
|
12
|
+
or services. For purposes of this license:
|
|
13
|
+
|
|
14
|
+
A "competitive offering" is a product or service that is offered
|
|
15
|
+
to third parties on a paid basis (including through paid support),
|
|
16
|
+
and that significantly overlaps with ToolPlex's platform, including:
|
|
17
|
+
tool discovery, tool execution, agent control, or workflow/playbook
|
|
18
|
+
reuse.
|
|
19
|
+
|
|
20
|
+
"Product" means software made available to end users or used to
|
|
21
|
+
operate hosted services.
|
|
22
|
+
|
|
23
|
+
"Embedded" includes incorporating source or binary components of
|
|
24
|
+
the Licensed Work into another product or requiring the Licensed
|
|
25
|
+
Work for that product to function.
|
|
26
|
+
|
|
27
|
+
"Internal use" within your organization is permitted, even for
|
|
28
|
+
commercial purposes, as long as it is not redistributed or offered
|
|
29
|
+
to others.
|
|
30
|
+
|
|
31
|
+
"API Integration Restrictions": Use of the ToolPlex API or services
|
|
32
|
+
to build, enhance, or operate a competitive offering is prohibited,
|
|
33
|
+
regardless of whether the Licensed Work is directly incorporated.
|
|
34
|
+
|
|
35
|
+
"Derivative Works": Includes any modification, adaptation, or custom
|
|
36
|
+
implementation based on the Licensed Work, including but not limited
|
|
37
|
+
to custom clients for ToolPlex API interaction. While permitted under
|
|
38
|
+
this license, such derivatives may present technical challenges and
|
|
39
|
+
are not officially supported.
|
|
40
|
+
|
|
41
|
+
"Research and Academic Use": Non-commercial research, educational,
|
|
42
|
+
and academic use is permitted regardless of competitive overlap,
|
|
43
|
+
provided results are not used to develop commercial competitive
|
|
44
|
+
offerings.
|
|
45
|
+
|
|
46
|
+
"Official Client Recommendation": While custom clients are permitted
|
|
47
|
+
under this license, ToolPlex strongly recommends using the official
|
|
48
|
+
client to ensure compatibility, security, and optimal performance.
|
|
49
|
+
|
|
50
|
+
Hosting or using the Licensed Work for internal purposes within an
|
|
51
|
+
organization is not considered a competitive offering. ToolPlex
|
|
52
|
+
considers your organization to include all of your affiliates under
|
|
53
|
+
common control.
|
|
54
|
+
|
|
55
|
+
Change Date: None
|
|
56
|
+
Change License: MPL 2.0
|
|
57
|
+
|
|
58
|
+
For information about alternative licensing arrangements for the Licensed Work,
|
|
59
|
+
please contact support@toolplex.ai.
|
|
60
|
+
|
|
61
|
+
Notice
|
|
62
|
+
|
|
63
|
+
Business Source License 1.1
|
|
64
|
+
|
|
65
|
+
Terms
|
|
66
|
+
|
|
67
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
68
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
69
|
+
Licensor may make an Additional Use Grant, above, permitting limited production use.
|
|
70
|
+
|
|
71
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
72
|
+
currently in effect as described in this License, you must purchase a
|
|
73
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
74
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
75
|
+
|
|
76
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
77
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
78
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
79
|
+
for each version of the Licensed Work released by Licensor.
|
|
80
|
+
|
|
81
|
+
You must conspicuously display this License on each original or modified copy
|
|
82
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
83
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
84
|
+
License apply to your use of that work.
|
|
85
|
+
|
|
86
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
87
|
+
terminate your rights under this License for the current and all other
|
|
88
|
+
versions of the Licensed Work.
|
|
89
|
+
|
|
90
|
+
This License does not grant you any right in any trademark or logo of
|
|
91
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
92
|
+
Licensor as expressly required by this License).
|
|
93
|
+
|
|
94
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
95
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
96
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
97
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
98
|
+
TITLE.
|
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# ToolPlex Client
|
|
2
|
+
|
|
3
|
+
[](https://toolplex.ai)
|
|
4
|
+
[](https://discord.gg/KpCjj8ay)
|
|
5
|
+
|
|
6
|
+
This repository contains the official **ToolPlex MCP server** — the npm package that enables AI agents to connect to the ToolPlex platform.
|
|
7
|
+
|
|
8
|
+
ToolPlex is a curated tool ecosystem built for AI agents. With ToolPlex, your agent can:
|
|
9
|
+
- 🔍 Discover 2,000+ high quality, open-source MCP tools
|
|
10
|
+
- 🛠️ Install and run tools with your permission
|
|
11
|
+
- 📚 Save workflows as reusable playbooks
|
|
12
|
+
- 🔁 Learn from success — your agent evolves from collective agent feedback
|
|
13
|
+
|
|
14
|
+
No complex setup. Just add ToolPlex to your AI client and start automating.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Agent Tool Discovery** — Your agent can search a curated index of MCP servers, filtered by code analysis and popularity signals to find tools that actually work
|
|
19
|
+
- **Smooth Install Experience** — Automatically installs even complex tools, with the agent handling tricky build steps, dependencies, and setup flows behind the scenes
|
|
20
|
+
- **Secure Config Handling** — Injects API keys, secrets, and file paths only when needed — always under your control
|
|
21
|
+
- **Seamless Server Activation** — Install and uninstall MCP servers at any time without restarting your LLM or resetting the session
|
|
22
|
+
- **Workflow Memory** — Successful tasks are saved as playbooks your agent can search, reuse, and adapt later
|
|
23
|
+
- **Quality Signals Built-In** — Agents report tool usage and failure rates to help down-rank unreliable or broken servers automatically
|
|
24
|
+
- **Team-Ready** — Share tools, playbooks, and permission sets across your org for faster onboarding and coordinated automation
|
|
25
|
+
- **Full Agent Control** — Use the ToolPlex dashboard to manage server access, shell permissions, file visibility, feedback settings, and more
|
|
26
|
+
- **Local-First Execution** — By default, ToolPlex installs and runs tools on your machine for full speed, privacy, and control
|
|
27
|
+
|
|
28
|
+
## Quick Setup
|
|
29
|
+
|
|
30
|
+
**Claude Desktop (recommended)**
|
|
31
|
+
1. Sign up for a [ToolPlex AI](https://toolplex.ai) account and create your first API key.
|
|
32
|
+
2. Install [Claude Desktop](https://claude.ai/download).
|
|
33
|
+
3. Add this to your `claude_desktop_config.json`:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"toolplex-mcp": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["@toolplex/client"],
|
|
41
|
+
"env": {
|
|
42
|
+
"TOOLPLEX_API_KEY": "YOUR_API_KEY_HERE"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or use any AI chat client that [supports MCP](https://github.com/punkpeye/awesome-mcp-clients).
|
|
50
|
+
|
|
51
|
+
ToolPlex works best as the **only server** in your MCP config, since it handles discovery, installation, and management of all other MCP servers on your behalf.
|
|
52
|
+
|
|
53
|
+
If you *must* include ToolPlex alongside other servers, be sure to **mention `toolplex` by name** when you want to use it. This helps your agent avoid ambiguity when multiple servers are present.
|
|
54
|
+
|
|
55
|
+
## ToolPlex Usage Guide
|
|
56
|
+
|
|
57
|
+
ToolPlex API users aren't humans — they're AI agents.
|
|
58
|
+
|
|
59
|
+
**You talk to your agent.** Your agent talks to ToolPlex. This allows agents to handle the full lifecycle of tool usage — from discovery and installation to configuration, execution, and playbook use — all without human micromanagement.
|
|
60
|
+
|
|
61
|
+
Ask your AI to activate ToolPlex:
|
|
62
|
+
```
|
|
63
|
+
> init toolplex
|
|
64
|
+
> start toolplex
|
|
65
|
+
> open toolplex
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
After initializing ToolPlex, just talk to your agent naturally:
|
|
69
|
+
|
|
70
|
+
### Discover Available Tools
|
|
71
|
+
```
|
|
72
|
+
> what tools are currently installed?
|
|
73
|
+
> show me what ToolPlex servers I can use
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Run Installed Tools
|
|
77
|
+
```
|
|
78
|
+
> merge these PDFs using the File Merger tool
|
|
79
|
+
> fetch the latest bitcoin price from Yahoo Finance
|
|
80
|
+
> find some tools to generate my weekly dinner menu
|
|
81
|
+
> extract tables from this Excel file using the Excel MCP
|
|
82
|
+
> query our BigQuery sales data for Q2 totals
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Install New Tools (via search)
|
|
86
|
+
```
|
|
87
|
+
> find a tool that can automate browser tests
|
|
88
|
+
> is there a server that can visualize data with charts?
|
|
89
|
+
> search for a tool that can read and organize research PDFs
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Manage Tools
|
|
93
|
+
```
|
|
94
|
+
> install the google news server
|
|
95
|
+
> uninstall the ffmpeg server
|
|
96
|
+
> reinstall the Playwright automation server
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Use Playbooks
|
|
100
|
+
```
|
|
101
|
+
> run my weekly KPI dashboard playbook
|
|
102
|
+
> save this as a playbook
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## LLM Compatability
|
|
106
|
+
ToolPlex works better with generalist, high-context LLMs that support tool-calling, like:
|
|
107
|
+
* `claude-sonnet-3.7`
|
|
108
|
+
* `claude-sonnet-4`
|
|
109
|
+
* `gpt-4o`
|
|
110
|
+
* `gpt-4.1`
|
|
111
|
+
|
|
112
|
+
Weaker reasoning models like `deepseek-chat` or `claude-haiku-3.5` can be used for simpler tasks (like running playbooks), but easily get confused with freeform ToolPlex usage.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { LLMContext } from '../shared/mcpServerTypes.js';
|
|
2
|
+
import { ClientPermissions, ClientFlags } from './toolplexApi/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Maintains client context for the ToolPlex server
|
|
5
|
+
*/
|
|
6
|
+
export declare class ClientContext {
|
|
7
|
+
private _sessionId;
|
|
8
|
+
private _dev;
|
|
9
|
+
private _apiKey;
|
|
10
|
+
private _clientMode;
|
|
11
|
+
private _llmContext;
|
|
12
|
+
private _clientVersion;
|
|
13
|
+
private _permissions;
|
|
14
|
+
private _flags;
|
|
15
|
+
private _isOrgUser;
|
|
16
|
+
get sessionId(): string;
|
|
17
|
+
set sessionId(id: string);
|
|
18
|
+
get dev(): boolean;
|
|
19
|
+
set dev(isDev: boolean);
|
|
20
|
+
get apiKey(): string;
|
|
21
|
+
set apiKey(key: string);
|
|
22
|
+
get clientMode(): 'standard' | 'restricted';
|
|
23
|
+
set clientMode(mode: 'standard' | 'restricted');
|
|
24
|
+
get llmContext(): LLMContext;
|
|
25
|
+
set llmContext(context: LLMContext);
|
|
26
|
+
get clientVersion(): string;
|
|
27
|
+
set clientVersion(version: string);
|
|
28
|
+
get permissions(): ClientPermissions;
|
|
29
|
+
set permissions(perms: ClientPermissions);
|
|
30
|
+
get flags(): ClientFlags;
|
|
31
|
+
set flags(consts: ClientFlags);
|
|
32
|
+
get isOrgUser(): boolean;
|
|
33
|
+
set isOrgUser(isOrgUser: boolean);
|
|
34
|
+
isInitialized(): boolean;
|
|
35
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maintains client context for the ToolPlex server
|
|
3
|
+
*/
|
|
4
|
+
export class ClientContext {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._sessionId = null;
|
|
7
|
+
this._dev = null;
|
|
8
|
+
this._apiKey = null;
|
|
9
|
+
this._clientMode = null;
|
|
10
|
+
this._llmContext = null;
|
|
11
|
+
this._clientVersion = null;
|
|
12
|
+
this._permissions = null;
|
|
13
|
+
this._flags = null;
|
|
14
|
+
this._isOrgUser = null;
|
|
15
|
+
}
|
|
16
|
+
get sessionId() {
|
|
17
|
+
if (!this._sessionId) {
|
|
18
|
+
throw new Error('Session ID not set - ToolPlex not initialized');
|
|
19
|
+
}
|
|
20
|
+
return this._sessionId;
|
|
21
|
+
}
|
|
22
|
+
set sessionId(id) {
|
|
23
|
+
this._sessionId = id;
|
|
24
|
+
}
|
|
25
|
+
get dev() {
|
|
26
|
+
if (this._dev === null) {
|
|
27
|
+
throw new Error('Dev mode not set - ToolPlex not initialized');
|
|
28
|
+
}
|
|
29
|
+
return this._dev;
|
|
30
|
+
}
|
|
31
|
+
set dev(isDev) {
|
|
32
|
+
this._dev = isDev;
|
|
33
|
+
}
|
|
34
|
+
get apiKey() {
|
|
35
|
+
if (!this._apiKey) {
|
|
36
|
+
throw new Error('API key not set - ToolPlex not initialized');
|
|
37
|
+
}
|
|
38
|
+
return this._apiKey;
|
|
39
|
+
}
|
|
40
|
+
set apiKey(key) {
|
|
41
|
+
this._apiKey = key;
|
|
42
|
+
}
|
|
43
|
+
get clientMode() {
|
|
44
|
+
if (!this._clientMode) {
|
|
45
|
+
throw new Error('Client mode not set - ToolPlex not initialized');
|
|
46
|
+
}
|
|
47
|
+
return this._clientMode;
|
|
48
|
+
}
|
|
49
|
+
set clientMode(mode) {
|
|
50
|
+
this._clientMode = mode;
|
|
51
|
+
}
|
|
52
|
+
get llmContext() {
|
|
53
|
+
if (!this._llmContext) {
|
|
54
|
+
throw new Error('LLM context not set - ToolPlex not initialized');
|
|
55
|
+
}
|
|
56
|
+
return this._llmContext;
|
|
57
|
+
}
|
|
58
|
+
set llmContext(context) {
|
|
59
|
+
this._llmContext = context;
|
|
60
|
+
}
|
|
61
|
+
get clientVersion() {
|
|
62
|
+
if (!this._clientVersion) {
|
|
63
|
+
throw new Error('Client version not set - ToolPlex not initialized');
|
|
64
|
+
}
|
|
65
|
+
return this._clientVersion;
|
|
66
|
+
}
|
|
67
|
+
set clientVersion(version) {
|
|
68
|
+
this._clientVersion = version;
|
|
69
|
+
}
|
|
70
|
+
get permissions() {
|
|
71
|
+
if (!this._permissions) {
|
|
72
|
+
throw new Error('Permissions not set - ToolPlex not initialized');
|
|
73
|
+
}
|
|
74
|
+
return this._permissions;
|
|
75
|
+
}
|
|
76
|
+
set permissions(perms) {
|
|
77
|
+
this._permissions = perms;
|
|
78
|
+
}
|
|
79
|
+
get flags() {
|
|
80
|
+
if (!this._flags) {
|
|
81
|
+
throw new Error('Consts not set - ToolPlex not initialized');
|
|
82
|
+
}
|
|
83
|
+
return this._flags;
|
|
84
|
+
}
|
|
85
|
+
set flags(consts) {
|
|
86
|
+
this._flags = consts;
|
|
87
|
+
}
|
|
88
|
+
get isOrgUser() {
|
|
89
|
+
if (this._isOrgUser === null) {
|
|
90
|
+
throw new Error('Organization user status not set - ToolPlex not initialized');
|
|
91
|
+
}
|
|
92
|
+
return this._isOrgUser;
|
|
93
|
+
}
|
|
94
|
+
set isOrgUser(isOrgUser) {
|
|
95
|
+
this._isOrgUser = isOrgUser;
|
|
96
|
+
}
|
|
97
|
+
isInitialized() {
|
|
98
|
+
return !!(this._sessionId &&
|
|
99
|
+
this._apiKey &&
|
|
100
|
+
this._clientMode &&
|
|
101
|
+
this._llmContext &&
|
|
102
|
+
this._clientVersion &&
|
|
103
|
+
this._permissions &&
|
|
104
|
+
this._flags &&
|
|
105
|
+
this._isOrgUser !== null);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { serve } from './toolplexServer.js';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
import { FileLogger } from '../shared/fileLogger.js';
|
|
5
|
+
dotenv.config();
|
|
6
|
+
FileLogger.initialize('mcp-server');
|
|
7
|
+
const isDev = process.env.DEV === 'true';
|
|
8
|
+
const apiKey = process.env.TOOLPLEX_API_KEY;
|
|
9
|
+
const clientMode = process.env.TOOLPLEX_CLIENT_MODE || 'standard';
|
|
10
|
+
const logLevel = process.env.LOG_LEVEL || 'info';
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
const config = {
|
|
15
|
+
dev: isDev,
|
|
16
|
+
apiKey,
|
|
17
|
+
clientMode,
|
|
18
|
+
logLevel,
|
|
19
|
+
};
|
|
20
|
+
serve(config).catch(() => {
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { LogTelemetryRequest } from '../toolplexApi/types.js';
|
|
2
|
+
export declare class TelemetryLogger {
|
|
3
|
+
private eventQueue;
|
|
4
|
+
private flushTimeout;
|
|
5
|
+
private readonly BATCH_SIZE;
|
|
6
|
+
private readonly FLUSH_INTERVAL;
|
|
7
|
+
constructor();
|
|
8
|
+
/**
|
|
9
|
+
* Log a telemetry event
|
|
10
|
+
*/
|
|
11
|
+
log(eventType: LogTelemetryRequest['event_type'], data: Partial<Omit<LogTelemetryRequest, 'event_type'>>): Promise<void>;
|
|
12
|
+
private flush;
|
|
13
|
+
private scheduleFlush;
|
|
14
|
+
/**
|
|
15
|
+
* Clean up resources - should be called when shutting down
|
|
16
|
+
*/
|
|
17
|
+
dispose(): Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import Registry from '../registry.js';
|
|
2
|
+
import { FileLogger } from '../../shared/fileLogger.js';
|
|
3
|
+
const logger = FileLogger;
|
|
4
|
+
export class TelemetryLogger {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.eventQueue = [];
|
|
7
|
+
this.flushTimeout = null;
|
|
8
|
+
this.BATCH_SIZE = 10;
|
|
9
|
+
this.FLUSH_INTERVAL = 30000;
|
|
10
|
+
this.scheduleFlush();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Log a telemetry event
|
|
14
|
+
*/
|
|
15
|
+
async log(eventType, data) {
|
|
16
|
+
this.eventQueue.push({ eventType, data });
|
|
17
|
+
if (this.eventQueue.length >= this.BATCH_SIZE) {
|
|
18
|
+
await this.flush();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async flush() {
|
|
22
|
+
if (this.eventQueue.length === 0)
|
|
23
|
+
return;
|
|
24
|
+
try {
|
|
25
|
+
const apiService = Registry.getToolplexApiService();
|
|
26
|
+
const events = [...this.eventQueue];
|
|
27
|
+
this.eventQueue = [];
|
|
28
|
+
await logger.debug(`Flushing ${events.length} telemetry events`);
|
|
29
|
+
await apiService.logTelemetryEvents(events);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
await logger.error(`Error flushing telemetry events: ${err}`);
|
|
33
|
+
this.eventQueue.unshift(...this.eventQueue);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
scheduleFlush() {
|
|
37
|
+
if (this.flushTimeout) {
|
|
38
|
+
clearTimeout(this.flushTimeout);
|
|
39
|
+
}
|
|
40
|
+
this.flushTimeout = setTimeout(async () => {
|
|
41
|
+
await this.flush();
|
|
42
|
+
this.scheduleFlush();
|
|
43
|
+
}, this.FLUSH_INTERVAL);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Clean up resources - should be called when shutting down
|
|
47
|
+
*/
|
|
48
|
+
async dispose() {
|
|
49
|
+
if (this.flushTimeout) {
|
|
50
|
+
clearTimeout(this.flushTimeout);
|
|
51
|
+
}
|
|
52
|
+
await this.flush();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare class CallToolObserver {
|
|
2
|
+
private serverToolCalls;
|
|
3
|
+
constructor();
|
|
4
|
+
recordCall(serverId: string, toolName: string): void;
|
|
5
|
+
wasServerCalled(serverId: string): boolean;
|
|
6
|
+
wasToolCalled(serverId: string, toolName: string): boolean;
|
|
7
|
+
clear(): void;
|
|
8
|
+
}
|
|
9
|
+
export default CallToolObserver;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class CallToolObserver {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.serverToolCalls = new Map();
|
|
4
|
+
}
|
|
5
|
+
// Record a call to a tool on a server
|
|
6
|
+
recordCall(serverId, toolName) {
|
|
7
|
+
if (!this.serverToolCalls.has(serverId)) {
|
|
8
|
+
this.serverToolCalls.set(serverId, new Set());
|
|
9
|
+
}
|
|
10
|
+
this.serverToolCalls.get(serverId).add(toolName);
|
|
11
|
+
}
|
|
12
|
+
// Check if a server was called at all
|
|
13
|
+
wasServerCalled(serverId) {
|
|
14
|
+
return this.serverToolCalls.has(serverId) && this.serverToolCalls.get(serverId).size > 0;
|
|
15
|
+
}
|
|
16
|
+
// Check if a specific tool was called on a server
|
|
17
|
+
wasToolCalled(serverId, toolName) {
|
|
18
|
+
return this.serverToolCalls.has(serverId) && this.serverToolCalls.get(serverId).has(toolName);
|
|
19
|
+
}
|
|
20
|
+
// Optionally, clear all records (for testing or reset)
|
|
21
|
+
clear() {
|
|
22
|
+
this.serverToolCalls.clear();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export default CallToolObserver;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import CallToolObserver from './callToolObserver.js';
|
|
2
|
+
import InstallObserver from './installObserver.js';
|
|
3
|
+
import { ClientContext } from '../clientContext.js';
|
|
4
|
+
import { SubmitFeedbackParams } from '../../shared/mcpServerTypes.js';
|
|
5
|
+
export declare class FeedbackPolicy {
|
|
6
|
+
private callToolObserver;
|
|
7
|
+
private installObserver;
|
|
8
|
+
private clientContext;
|
|
9
|
+
private blockedMcpServersSet;
|
|
10
|
+
constructor(clientContext: ClientContext, callToolObserver: CallToolObserver, installObserver: InstallObserver);
|
|
11
|
+
/**
|
|
12
|
+
* Validates feedback by checking that:
|
|
13
|
+
* - The referenced server has been used or had an install/uninstall action
|
|
14
|
+
* - The server is not in the blocked servers list
|
|
15
|
+
*
|
|
16
|
+
* For server feedback, verifies that:
|
|
17
|
+
* - The referenced server has been connected to and used or had an install/uninstall action
|
|
18
|
+
* - The server is not blocked
|
|
19
|
+
*
|
|
20
|
+
* For playbook feedback, no validation is currently performed
|
|
21
|
+
* since playbooks can reference other playbooks.
|
|
22
|
+
*
|
|
23
|
+
* @throws Error if feedback references a server that hasn't been used or had an install/uninstall action
|
|
24
|
+
* in the current session or if the server is blocked
|
|
25
|
+
*/
|
|
26
|
+
enforceFeedbackPolicy(feedback: SubmitFeedbackParams): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class FeedbackPolicy {
|
|
2
|
+
constructor(clientContext, callToolObserver, installObserver) {
|
|
3
|
+
this.callToolObserver = callToolObserver;
|
|
4
|
+
this.installObserver = installObserver;
|
|
5
|
+
this.clientContext = clientContext;
|
|
6
|
+
this.blockedMcpServersSet = new Set(clientContext.flags.blocked_mcp_servers || []);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Validates feedback by checking that:
|
|
10
|
+
* - The referenced server has been used or had an install/uninstall action
|
|
11
|
+
* - The server is not in the blocked servers list
|
|
12
|
+
*
|
|
13
|
+
* For server feedback, verifies that:
|
|
14
|
+
* - The referenced server has been connected to and used or had an install/uninstall action
|
|
15
|
+
* - The server is not blocked
|
|
16
|
+
*
|
|
17
|
+
* For playbook feedback, no validation is currently performed
|
|
18
|
+
* since playbooks can reference other playbooks.
|
|
19
|
+
*
|
|
20
|
+
* @throws Error if feedback references a server that hasn't been used or had an install/uninstall action
|
|
21
|
+
* in the current session or if the server is blocked
|
|
22
|
+
*/
|
|
23
|
+
enforceFeedbackPolicy(feedback) {
|
|
24
|
+
const { target_type, target_id } = feedback;
|
|
25
|
+
if (target_type === 'server') {
|
|
26
|
+
// Check if server is blocked
|
|
27
|
+
if (this.blockedMcpServersSet.has(target_id)) {
|
|
28
|
+
throw new Error(`Cannot submit feedback for blocked server "${target_id}"`);
|
|
29
|
+
}
|
|
30
|
+
// For server feedback, verify the server was actually used or had an install/uninstall action
|
|
31
|
+
if (!this.callToolObserver.wasServerCalled(target_id) &&
|
|
32
|
+
!this.installObserver.wasServerInstalled(target_id) &&
|
|
33
|
+
!this.installObserver.wasServerUninstalled(target_id)) {
|
|
34
|
+
throw new Error(`Cannot submit feedback for server "${target_id}" which has not been used or had an install/uninstall action in this session.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// For playbook feedback, we don't validate usage since playbooks can reference other playbooks
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare class InstallObserver {
|
|
2
|
+
private serverInstallActions;
|
|
3
|
+
constructor();
|
|
4
|
+
recordInstall(serverId: string): void;
|
|
5
|
+
recordUninstall(serverId: string): void;
|
|
6
|
+
wasServerInstalled(serverId: string): boolean;
|
|
7
|
+
wasServerUninstalled(serverId: string): boolean;
|
|
8
|
+
clear(): void;
|
|
9
|
+
private recordAction;
|
|
10
|
+
}
|
|
11
|
+
export default InstallObserver;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
class InstallObserver {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.serverInstallActions = new Map();
|
|
4
|
+
}
|
|
5
|
+
// Record an install action on a server
|
|
6
|
+
recordInstall(serverId) {
|
|
7
|
+
this.recordAction(serverId, 'install');
|
|
8
|
+
}
|
|
9
|
+
// Record an uninstall action on a server
|
|
10
|
+
recordUninstall(serverId) {
|
|
11
|
+
this.recordAction(serverId, 'uninstall');
|
|
12
|
+
}
|
|
13
|
+
// Check if a server has been installed
|
|
14
|
+
wasServerInstalled(serverId) {
|
|
15
|
+
return (this.serverInstallActions.has(serverId) &&
|
|
16
|
+
this.serverInstallActions.get(serverId).has('install'));
|
|
17
|
+
}
|
|
18
|
+
// Check if a server has been uninstalled
|
|
19
|
+
wasServerUninstalled(serverId) {
|
|
20
|
+
return (this.serverInstallActions.has(serverId) &&
|
|
21
|
+
this.serverInstallActions.get(serverId).has('uninstall'));
|
|
22
|
+
}
|
|
23
|
+
// Optionally, clear all records (for testing or reset)
|
|
24
|
+
clear() {
|
|
25
|
+
this.serverInstallActions.clear();
|
|
26
|
+
}
|
|
27
|
+
// Private method to record an action
|
|
28
|
+
recordAction(serverId, action) {
|
|
29
|
+
if (!this.serverInstallActions.has(serverId)) {
|
|
30
|
+
this.serverInstallActions.set(serverId, new Set());
|
|
31
|
+
}
|
|
32
|
+
this.serverInstallActions.get(serverId).add(action);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export default InstallObserver;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import CallToolObserver from './callToolObserver.js';
|
|
2
|
+
import { ClientContext } from '../clientContext.js';
|
|
3
|
+
import { SavePlaybookParams } from '../../shared/mcpServerTypes.js';
|
|
4
|
+
export declare class PlaybookPolicy {
|
|
5
|
+
private callToolObserver;
|
|
6
|
+
private clientContext;
|
|
7
|
+
private blockedMcpServersSet;
|
|
8
|
+
constructor(clientContext: ClientContext, callToolObserver: CallToolObserver);
|
|
9
|
+
/**
|
|
10
|
+
* Validates a playbook before saving by checking that:
|
|
11
|
+
* - Referenced servers and tools have been used
|
|
12
|
+
* - No blocked servers are referenced
|
|
13
|
+
* - Private playbooks are only created when enabled
|
|
14
|
+
*
|
|
15
|
+
* For each action with a 'call' property, verifies that:
|
|
16
|
+
* - Any referenced server has been connected to
|
|
17
|
+
* - Any referenced server/tool combination has been executed
|
|
18
|
+
* - The server is not in the blocked servers list
|
|
19
|
+
*
|
|
20
|
+
* @throws Error if a referenced server or tool has not been used in the current session,
|
|
21
|
+
* if a blocked server is referenced, or if trying to create a private playbook when disabled
|
|
22
|
+
*/
|
|
23
|
+
enforceSavePlaybookPolicy(playbook: SavePlaybookParams): void;
|
|
24
|
+
/**
|
|
25
|
+
* Validates if playbook usage logging is allowed based on read-only mode
|
|
26
|
+
* @throws Error if read-only mode is enabled
|
|
27
|
+
*/
|
|
28
|
+
enforceLogPlaybookUsagePolicy(): void;
|
|
29
|
+
}
|