@vruum/mcp 0.2.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 +21 -0
- package/README.md +66 -0
- package/dist/index.js +229 -0
- package/package.json +54 -0
- package/tools.json +2528 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vruum (vruum-gtm)
|
|
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,66 @@
|
|
|
1
|
+
# Vruum MCP (`@vruum/mcp`)
|
|
2
|
+
|
|
3
|
+
Official MCP access to [Vruum](https://vruum.ai) — the AI revenue platform. Operate outbound, deals, pipeline, and CRM automation from your agent: people, deals, outreach, engagement, and research tools over one MCP.
|
|
4
|
+
|
|
5
|
+
This package is the **stdio bridge** to the hosted Vruum MCP server. It serves the advertised tool surface locally (no credentials needed to introspect) and proxies tool execution to `https://api.vruum.ai/mcp` under your Vruum token. Every call is authorized server-side; the bridge grants no authority beyond what your Vruum account can already do.
|
|
6
|
+
|
|
7
|
+
> **Connecting a modern client? Prefer the remote server directly.**
|
|
8
|
+
> Clients that support remote MCP (Claude Code, Claude Desktop, Cursor, Codex, …) should connect straight to `https://api.vruum.ai/mcp` (OAuth 2.1, or `Authorization: Bearer vk_live_…`). This bridge exists for stdio-only clients and for tool-surface introspection. See [vruum.ai/docs/mcp](https://vruum.ai/docs/mcp).
|
|
9
|
+
|
|
10
|
+
## Install & connect
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"vruum": {
|
|
16
|
+
"command": "npx",
|
|
17
|
+
"args": ["-y", "@vruum/mcp"],
|
|
18
|
+
"env": { "VRUUM_MCP_TOKEN": "vk_live_…" }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Get a token in the Vruum web app under **Settings → API tokens**. A Vruum account is required to execute tools; listing tools works without one.
|
|
25
|
+
|
|
26
|
+
Already using the CLI? `npx @vruum/cli` → `vruum login --token vk_live_…` stores credentials in `~/.vruum/credentials`, and the bridge picks them up automatically.
|
|
27
|
+
|
|
28
|
+
### Configuration
|
|
29
|
+
|
|
30
|
+
| Env var | Meaning | Default |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `VRUUM_MCP_TOKEN` | Vruum personal access token | — (falls back to `VRUUM_TOKEN`, then `~/.vruum/credentials`) |
|
|
33
|
+
| `VRUUM_MCP_URL` | Hosted MCP endpoint | `https://api.vruum.ai/mcp` |
|
|
34
|
+
| `VRUUM_MCP_TIMEOUT_MS` | Per-call timeout (research/import tools run long) | `300000` |
|
|
35
|
+
| `VRUUM_CONFIG_DIR` | Credentials directory | `~/.vruum` |
|
|
36
|
+
|
|
37
|
+
## What's inside
|
|
38
|
+
|
|
39
|
+
- **[`tools.json`](tools.json)** — the client-advertised tool surface: **29 curated compound tools** (`search`, `fetch`, `research`, `skill`, and the `manage_*` / `get_*` families covering people, deals, outreach, engagement, content, campaigns, and revenue), each carrying MCP safety annotations. This is exactly what a real Vruum session is advertised — one tool per decision rather than a sprawl of granular endpoints, so an agent never has to disambiguate between overlapping legacy verbs. Generated from the live server definition and served verbatim for `tools/list`.
|
|
40
|
+
- **[`src/index.ts`](src/index.ts)** — the bridge: static listings, proxied calls, and structured errors
|
|
41
|
+
(a missing token is an explanation, not a crash). **A failed call is never automatically
|
|
42
|
+
retried** — many of these tools send outreach or spend money, and an ambiguous failure may
|
|
43
|
+
mean the server already executed, so a silent replay could double-send. The dead connection
|
|
44
|
+
is discarded, the error says so, and your agent decides whether the tool is safe to re-run.
|
|
45
|
+
|
|
46
|
+
The distinctive design position of the Vruum MCP: **your AI harness authors all sales and marketing prose.** The server schedules, gates, persists, and sends — it has no server-side message generation. Outreach drafts surface to your agent as work items rather than being written for you.
|
|
47
|
+
|
|
48
|
+
## Development
|
|
49
|
+
|
|
50
|
+
This repository is a **build artifact of the Vruum monorepo**, resynced automatically on release — `tools.json` is regenerated from the live server definition, so it never drifts from what the hosted server actually exposes.
|
|
51
|
+
|
|
52
|
+
Issues and PRs are welcome here: maintainers upstream accepted changes into the monorepo, and they flow back on the next sync.
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
npm install
|
|
56
|
+
npm test # builds, then black-box JSON-RPC tests against the built binary
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Links
|
|
60
|
+
|
|
61
|
+
- [Vruum](https://vruum.ai) · [MCP docs](https://vruum.ai/docs/mcp) · [Getting started](https://vruum.ai/docs/getting-started)
|
|
62
|
+
- Official registry entry: `ai.vruum/mcp` · Claude/Codex plugin: [`vruum-gtm/skills`](https://github.com/vruum-gtm/skills)
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
[MIT](LICENSE)
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @vruum/mcp — stdio bridge for the hosted Vruum MCP.
|
|
4
|
+
*
|
|
5
|
+
* Two jobs, deliberately small:
|
|
6
|
+
*
|
|
7
|
+
* 1. `tools/list` is served STATICALLY from the bundled `tools.json` (the
|
|
8
|
+
* member-visible surface of https://api.vruum.ai/mcp, generated in the
|
|
9
|
+
* Vruum monorepo by `backend/scripts/dump_member_tools.py`). This is what
|
|
10
|
+
* lets registry crawlers and stdio-only clients introspect the tool
|
|
11
|
+
* surface without credentials.
|
|
12
|
+
*
|
|
13
|
+
* 2. `tools/call` proxies to the hosted server over Streamable HTTP with the
|
|
14
|
+
* caller's Vruum token. Without a token, calls return a structured error
|
|
15
|
+
* explaining how to get one — never a hang or a crash.
|
|
16
|
+
*
|
|
17
|
+
* Token resolution (mirrors @vruum/cli's `lib/config.ts` precedence):
|
|
18
|
+
* VRUUM_MCP_TOKEN env > VRUUM_TOKEN env > ~/.vruum/credentials (written by
|
|
19
|
+
* `vruum login`; directory overridable via VRUUM_CONFIG_DIR).
|
|
20
|
+
*
|
|
21
|
+
* Endpoint resolution:
|
|
22
|
+
* VRUUM_MCP_URL env > credentials apiUrl + "/mcp" > https://api.vruum.ai/mcp
|
|
23
|
+
*
|
|
24
|
+
* Note: `tools.json` intentionally carries no outputSchema — declaring one
|
|
25
|
+
* would make this bridge's local error responses (which have no
|
|
26
|
+
* structuredContent) protocol violations under SDK output validation.
|
|
27
|
+
*/
|
|
28
|
+
import { readFileSync } from "node:fs";
|
|
29
|
+
import { homedir } from "node:os";
|
|
30
|
+
import { dirname, join } from "node:path";
|
|
31
|
+
import { fileURLToPath } from "node:url";
|
|
32
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
33
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
34
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
35
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
36
|
+
import { CallToolRequestSchema, CallToolResultSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
37
|
+
const DEFAULT_MCP_URL = "https://api.vruum.ai/mcp";
|
|
38
|
+
// The SDK's per-request default is 60s, which real Vruum tools (research,
|
|
39
|
+
// imports) legitimately exceed. Overridable via VRUUM_MCP_TIMEOUT_MS.
|
|
40
|
+
const DEFAULT_CALL_TIMEOUT_MS = 300_000;
|
|
41
|
+
function resolveCallTimeoutMs() {
|
|
42
|
+
const raw = Number(process.env.VRUUM_MCP_TIMEOUT_MS);
|
|
43
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CALL_TIMEOUT_MS;
|
|
44
|
+
}
|
|
45
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
46
|
+
// dist/index.js → package root sibling tools.json (also works from src/ via tsx).
|
|
47
|
+
const TOOLS_PATH = join(HERE, "..", "tools.json");
|
|
48
|
+
const PKG_PATH = join(HERE, "..", "package.json");
|
|
49
|
+
function readJson(path) {
|
|
50
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
51
|
+
}
|
|
52
|
+
function readCredentials() {
|
|
53
|
+
try {
|
|
54
|
+
const dir = process.env.VRUUM_CONFIG_DIR || join(homedir(), ".vruum");
|
|
55
|
+
const parsed = readJson(join(dir, "credentials"));
|
|
56
|
+
if (!parsed || typeof parsed.token !== "string" || !parsed.token)
|
|
57
|
+
return null;
|
|
58
|
+
return parsed;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function resolveToken(creds) {
|
|
65
|
+
return (process.env.VRUUM_MCP_TOKEN || process.env.VRUUM_TOKEN || creds?.token || null);
|
|
66
|
+
}
|
|
67
|
+
function resolveMcpUrl(creds) {
|
|
68
|
+
if (process.env.VRUUM_MCP_URL)
|
|
69
|
+
return process.env.VRUUM_MCP_URL;
|
|
70
|
+
if (creds?.apiUrl)
|
|
71
|
+
return creds.apiUrl.replace(/\/+$/, "") + "/mcp";
|
|
72
|
+
return DEFAULT_MCP_URL;
|
|
73
|
+
}
|
|
74
|
+
const NO_TOKEN_HELP = [
|
|
75
|
+
"No Vruum token configured, so this call was not sent.",
|
|
76
|
+
"",
|
|
77
|
+
"The bridge needs a Vruum personal access token to execute tools:",
|
|
78
|
+
" 1. Sign in at https://vruum.ai and create a token under Settings → API tokens (vk_live_…),",
|
|
79
|
+
" 2. then either `export VRUUM_MCP_TOKEN=<token>` for this client,",
|
|
80
|
+
" or run `npx @vruum/cli` → `vruum login --token <token>` once.",
|
|
81
|
+
"",
|
|
82
|
+
"If your MCP client supports remote servers, prefer connecting it directly to",
|
|
83
|
+
`${DEFAULT_MCP_URL} (OAuth) instead of this stdio bridge.`,
|
|
84
|
+
].join("\n");
|
|
85
|
+
function errorResult(text) {
|
|
86
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Lazily-connected client to the hosted server.
|
|
90
|
+
*
|
|
91
|
+
* Failure semantics, deliberately conservative: a failed `tools/call` is
|
|
92
|
+
* NEVER automatically retried. Many Vruum tools mutate state, send outreach
|
|
93
|
+
* externally, or spend money, and an ambiguous failure (timeout, dropped
|
|
94
|
+
* response) may mean the server already executed — a client-side replay could
|
|
95
|
+
* double-send. The failed connection is discarded so the NEXT call gets a
|
|
96
|
+
* fresh session, the error is surfaced structurally, and the calling harness
|
|
97
|
+
* decides whether the tool is safe to retry. (This mirrors Vruum's own
|
|
98
|
+
* server-side durable-send-intent discipline: ambiguous outcomes park, they
|
|
99
|
+
* are not replayed.)
|
|
100
|
+
*/
|
|
101
|
+
class RemoteProxy {
|
|
102
|
+
url;
|
|
103
|
+
token;
|
|
104
|
+
version;
|
|
105
|
+
client = null;
|
|
106
|
+
/** Serializes connection creation so concurrent first calls share one
|
|
107
|
+
* client instead of racing to overwrite `this.client` (and later closing
|
|
108
|
+
* each other's healthy connections). */
|
|
109
|
+
connecting = null;
|
|
110
|
+
constructor(url, token, version) {
|
|
111
|
+
this.url = url;
|
|
112
|
+
this.token = token;
|
|
113
|
+
this.version = version;
|
|
114
|
+
}
|
|
115
|
+
getClient() {
|
|
116
|
+
if (this.client)
|
|
117
|
+
return Promise.resolve(this.client);
|
|
118
|
+
if (!this.connecting) {
|
|
119
|
+
this.connecting = (async () => {
|
|
120
|
+
const transport = new StreamableHTTPClientTransport(new URL(this.url), {
|
|
121
|
+
requestInit: {
|
|
122
|
+
headers: { Authorization: `Bearer ${this.token}` },
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
const client = new Client({ name: "vruum-mcp-bridge", version: this.version }, { capabilities: {} });
|
|
126
|
+
await client.connect(transport);
|
|
127
|
+
this.client = client;
|
|
128
|
+
return client;
|
|
129
|
+
})().finally(() => {
|
|
130
|
+
this.connecting = null;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return this.connecting;
|
|
134
|
+
}
|
|
135
|
+
/** Discard `failed` only if it is still the current client — a concurrent
|
|
136
|
+
* call may already have replaced it with a healthy connection. */
|
|
137
|
+
discard(failed) {
|
|
138
|
+
if (this.client === failed)
|
|
139
|
+
this.client = null;
|
|
140
|
+
void failed.close().catch(() => {
|
|
141
|
+
/* already dead */
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Raw tools/call — deliberately NOT `client.callTool()`: the helper
|
|
146
|
+
* validates results against outputSchemas cached by `listTools()`, and the
|
|
147
|
+
* remote advertises outputSchemas this bridge intentionally does not. The
|
|
148
|
+
* raw request form has no cache and no validation, so passthrough stays
|
|
149
|
+
* passthrough. Timeout is raised above the SDK's 60s default because real
|
|
150
|
+
* Vruum tools (research, imports) legitimately run longer.
|
|
151
|
+
*/
|
|
152
|
+
rawCall(client, name, args) {
|
|
153
|
+
return client.request({ method: "tools/call", params: { name, arguments: args } }, CallToolResultSchema, { timeout: resolveCallTimeoutMs(), resetTimeoutOnProgress: true });
|
|
154
|
+
}
|
|
155
|
+
async call(name, args) {
|
|
156
|
+
let client;
|
|
157
|
+
try {
|
|
158
|
+
client = await this.getClient();
|
|
159
|
+
}
|
|
160
|
+
catch (connectErr) {
|
|
161
|
+
// First-connect failures (DNS, invalid token, endpoint down) get the
|
|
162
|
+
// same structured error path as call failures — never a raw handler
|
|
163
|
+
// throw that surfaces as an opaque JSON-RPC internal error.
|
|
164
|
+
const msg = connectErr instanceof Error ? connectErr.message : String(connectErr);
|
|
165
|
+
return errorResult(`Could not connect to the Vruum MCP at ${this.url}: ${msg}\n` +
|
|
166
|
+
"Check that your token is valid (Settings → API tokens) and the " +
|
|
167
|
+
"endpoint is reachable.");
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
return await this.rawCall(client, name, args);
|
|
171
|
+
}
|
|
172
|
+
catch (callErr) {
|
|
173
|
+
this.discard(client);
|
|
174
|
+
const msg = callErr instanceof Error ? callErr.message : String(callErr);
|
|
175
|
+
return errorResult(`Vruum MCP call '${name}' failed against ${this.url}: ${msg}\n` +
|
|
176
|
+
"NOT automatically retried — the server may or may not have executed " +
|
|
177
|
+
"the action, and replaying a send/spend tool could duplicate it. " +
|
|
178
|
+
"Verify state with a read tool (e.g. fetch/search) before retrying; " +
|
|
179
|
+
"the next call will use a fresh connection.");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async function main() {
|
|
184
|
+
const pkg = readJson(PKG_PATH);
|
|
185
|
+
const toolsDoc = readJson(TOOLS_PATH);
|
|
186
|
+
const creds = readCredentials();
|
|
187
|
+
const token = resolveToken(creds);
|
|
188
|
+
const mcpUrl = resolveMcpUrl(creds);
|
|
189
|
+
const proxy = token ? new RemoteProxy(mcpUrl, token, pkg.version) : null;
|
|
190
|
+
const server = new Server({ name: "vruum-mcp", version: pkg.version }, {
|
|
191
|
+
// `listChanged: false` is the honest declaration: the listing is a
|
|
192
|
+
// static snapshot bundled at release time, so this server never emits
|
|
193
|
+
// notifications/tools/list_changed.
|
|
194
|
+
capabilities: { tools: { listChanged: false } },
|
|
195
|
+
instructions: "Bridge to the hosted Vruum revenue-platform MCP. Tool listings are " +
|
|
196
|
+
"served locally; tool calls execute against " +
|
|
197
|
+
`${mcpUrl} under your Vruum token and are authorized server-side.`,
|
|
198
|
+
});
|
|
199
|
+
server.setRequestHandler(ListToolsRequestSchema, async (request) => {
|
|
200
|
+
// The full list is returned in one page, so `nextCursor` is never set and
|
|
201
|
+
// a client can never legitimately hold a cursor for this server. Spec:
|
|
202
|
+
// "Invalid cursors SHOULD result in an error with code -32602."
|
|
203
|
+
const cursor = request.params?.cursor;
|
|
204
|
+
if (cursor !== undefined) {
|
|
205
|
+
throw new McpError(ErrorCode.InvalidParams, "Invalid cursor: this server returns all tools in a single page and " +
|
|
206
|
+
"never issues a nextCursor.");
|
|
207
|
+
}
|
|
208
|
+
return { tools: toolsDoc.tools };
|
|
209
|
+
});
|
|
210
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
211
|
+
const { name, arguments: args } = request.params;
|
|
212
|
+
// Spec (server/tools#error-handling): errors in *finding* the tool are
|
|
213
|
+
// PROTOCOL errors, not `isError` results — only errors originating from a
|
|
214
|
+
// tool's execution use `isError: true` (so the model can self-correct).
|
|
215
|
+
if (!toolsDoc.tools.some((t) => t.name === name)) {
|
|
216
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown tool: ${name}`);
|
|
217
|
+
}
|
|
218
|
+
// A missing token IS an execution error — the tool exists and the model
|
|
219
|
+
// should see why it could not run.
|
|
220
|
+
if (!proxy)
|
|
221
|
+
return errorResult(NO_TOKEN_HELP);
|
|
222
|
+
return proxy.call(name, (args ?? {}));
|
|
223
|
+
});
|
|
224
|
+
await server.connect(new StdioServerTransport());
|
|
225
|
+
}
|
|
226
|
+
main().catch((err) => {
|
|
227
|
+
console.error(`vruum-mcp fatal: ${err instanceof Error ? err.message : err}`);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vruum/mcp",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"mcpName": "ai.vruum/mcp",
|
|
5
|
+
"description": "Stdio MCP bridge for the hosted Vruum revenue-platform MCP (https://api.vruum.ai/mcp): serves the advertised tool surface for credential-free introspection and proxies tool calls with your Vruum token.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"vruum-mcp": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/vruum-gtm/mcp.git"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://vruum.ai/docs/mcp",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/vruum-gtm/mcp/issues"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"tools.json",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc -p tsconfig.json",
|
|
31
|
+
"postbuild": "chmod +x dist/index.js",
|
|
32
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
33
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
34
|
+
"prepublishOnly": "npm run typecheck && npm run test"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^24.0.0",
|
|
41
|
+
"typescript": "^5.7.0"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"vruum",
|
|
45
|
+
"mcp",
|
|
46
|
+
"mcp-server",
|
|
47
|
+
"model-context-protocol",
|
|
48
|
+
"sales",
|
|
49
|
+
"crm",
|
|
50
|
+
"revenue",
|
|
51
|
+
"outreach",
|
|
52
|
+
"gtm"
|
|
53
|
+
]
|
|
54
|
+
}
|