Sign In

@proventools/mcp

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@proventools/mcp - npm Package Compare versions

Comparing version
0.1.0-beta.1
to
0.1.0-beta.2
+66
-8
index.js
#!/usr/bin/env node
const SERVER_VERSION = "0.1.0-beta.1";
import { constants as fsConstants } from "node:fs";
import { open } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
const SERVER_VERSION = "0.1.0-beta.2";
const PROTOCOL_VERSION = "2024-11-05";
const API_KEY_PATTERN = /^pt_live_[a-f0-9]{32}$/;
const DEFAULT_API_ORIGIN = "https://www.proventools.net";

@@ -19,2 +25,5 @@ const TRUSTED_API_ORIGINS = new Set([

const REQUEST_TIMEOUT_MS = 20_000;
const MAX_CONFIG_BYTES = 16 * 1024;
const CONFIG_PATH = path.join(os.homedir(), ".config", "proventools", "config.json");
const NOFOLLOW_FLAG = typeof fsConstants.O_NOFOLLOW === "number" ? fsConstants.O_NOFOLLOW : 0;

@@ -303,8 +312,7 @@ const ZERO_CREDIT = "Credit cost: 0. Reads stored ProvenTools data only.";

function apiKey() {
const key = (process.env.PROVENTOOLS_API_KEY || "").trim();
if (!key) {
throw new ToolError(
"PROVENTOOLS_API_KEY is not set — get a key at www.proventools.net/dashboard/api-keys."
);
function validatedApiKey(value) {
const key = typeof value === "string" ? value.trim() : "";
if (!key) return "";
if (!API_KEY_PATTERN.test(key)) {
throw new ToolError("The configured ProvenTools API key has an invalid format.");
}

@@ -314,2 +322,52 @@ return key;

async function storedApiKey() {
let handle;
try {
handle = await open(CONFIG_PATH, fsConstants.O_RDONLY | NOFOLLOW_FLAG);
} catch (error) {
if (error?.code === "ENOENT") return "";
if (error?.code === "ELOOP") {
throw new ToolError("Refusing to read a symlinked ProvenTools config file.");
}
throw new ToolError("Could not open the ProvenTools config file. Run “proventools login” to replace it.");
}
try {
const metadata = await handle.stat();
if (!metadata.isFile()) {
throw new ToolError("Refusing to read an unsafe ProvenTools config file.");
}
if (metadata.size > MAX_CONFIG_BYTES) {
throw new ToolError("Refusing to read an oversized ProvenTools config file.");
}
if (process.platform !== "win32" && (metadata.mode & 0o077) !== 0) {
throw new ToolError(
"Refusing to read the ProvenTools config because it is accessible by other users. Run “proventools login” to recreate it securely."
);
}
if (typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
throw new ToolError("Refusing to read a ProvenTools config owned by another user.");
}
try {
return validatedApiKey(JSON.parse(await handle.readFile("utf8"))?.apiKey);
} catch (error) {
if (error instanceof ToolError) throw error;
throw new ToolError("Could not read the ProvenTools config file. Run “proventools login” to replace it.");
}
} finally {
await handle.close().catch(() => {});
}
}
async function apiKey() {
const environmentKey = validatedApiKey(process.env.PROVENTOOLS_API_KEY);
if (environmentKey) return environmentKey;
const key = await storedApiKey();
if (key) return key;
throw new ToolError(
"Not logged in. Run “proventools login” or set PROVENTOOLS_API_KEY."
);
}
async function readResponseText(response) {

@@ -359,3 +417,3 @@ const declaredLength = Number(response.headers.get("content-length"));

const headers = {
Authorization: `Bearer ${apiKey()}`,
Authorization: `Bearer ${await apiKey()}`,
Accept: responseType === "text" ? "text/markdown" : "application/json",

@@ -362,0 +420,0 @@ "User-Agent": `proventools-mcp/${SERVER_VERSION}`,

+1
-1
{
"name": "@proventools/mcp",
"version": "0.1.0-beta.1",
"version": "0.1.0-beta.2",
"description": "Read-only local MCP server for the ProvenTools idea library",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -13,5 +13,7 @@ # ProvenTools MCP server

Make `PROVENTOOLS_API_KEY` available through the MCP client's secret store or
inherited environment. Never place a literal key in command arguments, shell
history, checked-in MCP configuration, an agent prompt, or a log.
Run `proventools login` once to save the key in the private ProvenTools CLI
config. The MCP server reuses that file and prefers `PROVENTOOLS_API_KEY` when
your MCP client provides it through a secret store or inherited environment.
Never place a literal key in command arguments, shell history, checked-in MCP
configuration, an agent prompt, or a log.

@@ -24,3 +26,3 @@ The examples pin the exact beta version so an agent cannot silently execute a

```sh
codex mcp add proventools -- npx --yes @proventools/mcp@0.1.0-beta.1
codex mcp add proventools -- npx --yes @proventools/mcp@0.1.0-beta.2
```

@@ -31,3 +33,3 @@

```sh
claude mcp add proventools -- npx --yes @proventools/mcp@0.1.0-beta.1
claude mcp add proventools -- npx --yes @proventools/mcp@0.1.0-beta.2
```

@@ -44,3 +46,3 @@

"command": "npx",
"args": ["--yes", "@proventools/mcp@0.1.0-beta.1"]
"args": ["--yes", "@proventools/mcp@0.1.0-beta.2"]
}

@@ -56,3 +58,3 @@ }

"command": "npx",
"args": ["--yes", "@proventools/mcp@0.1.0-beta.1"]
"args": ["--yes", "@proventools/mcp@0.1.0-beta.2"]
}

@@ -59,0 +61,0 @@ ```