From 297cd43621e80e60d523fdf3e6c4bcd76b95abf4 Mon Sep 17 00:00:00 2001 From: Volod Date: Thu, 8 Oct 2026 08:46:42 -0700 Subject: [PATCH 1/2] feat(server): sign MCP connection grants for one year `vana server start` passes mcpGrantTtlSeconds = 365 days to the Personal Server, so grants it signs itself for MCP connections expire after a year instead of never. Takes effect once the runtime pins a personal-server-ts release with the option; older servers ignore it. Claude-Session: https://claude.ai/code/session_01Fcv6uEy4zcXaigzDNxeW3j --- .../local/runtime-pkg/derived-config.mjs | 7 +++++++ src/personal-server/local/runtime-pkg/entry.mjs | 9 ++++++++- test/personal-server/derived-config.test.ts | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/personal-server/local/runtime-pkg/derived-config.mjs b/src/personal-server/local/runtime-pkg/derived-config.mjs index 01535cf..2b9a886 100644 --- a/src/personal-server/local/runtime-pkg/derived-config.mjs +++ b/src/personal-server/local/runtime-pkg/derived-config.mjs @@ -2,6 +2,13 @@ // the tunnel client, and how it lands on a persisted server.json. Kept apart // from entry.mjs so it can be tested without starting a server. +// Lifetime of the grants the server signs itself for MCP connections (an +// agent connecting over OAuth, or a scope request approved with no live +// grant to inherit an expiry from): one year from signing. Needs +// personal-server-ts with `mcpGrantTtlSeconds`; an older server ignores the +// option and keeps signing perpetual grants. +export const MCP_GRANT_TTL_SECONDS = 365 * 24 * 3600; + function isPlainObject(value) { return ( typeof value === "object" && diff --git a/src/personal-server/local/runtime-pkg/entry.mjs b/src/personal-server/local/runtime-pkg/entry.mjs index 602315c..8d7ef68 100644 --- a/src/personal-server/local/runtime-pkg/entry.mjs +++ b/src/personal-server/local/runtime-pkg/entry.mjs @@ -23,7 +23,11 @@ import { } from "@opendatalabs/personal-server-ts/node"; import { vanaWebMcpScopeRequestApprovalUrl } from "@opendatalabs/personal-server-ts-core/mcp"; -import { applyDerived, derivedConfig } from "./derived-config.mjs"; +import { + applyDerived, + derivedConfig, + MCP_GRANT_TTL_SECONDS, +} from "./derived-config.mjs"; import { startMcpApprovalPage } from "./mcp-approval.mjs"; const send = (message) => process.stdout.write(`${JSON.stringify(message)}\n`); @@ -197,6 +201,9 @@ async function main() { mcpScopeRequestApprovalUrl: vanaWebMcpScopeRequestApprovalUrl({ webOrigin: network.webOrigin, }), + // MCP connection grants this server signs expire after a year instead + // of never. A live grant's expiry is always kept on a scope request. + mcpGrantTtlSeconds: MCP_GRANT_TTL_SECONDS, configDefaults, onStatus: (status) => process.stderr.write(`[status] ${status}\n`), }); diff --git a/test/personal-server/derived-config.test.ts b/test/personal-server/derived-config.test.ts index f064722..ed3bf49 100644 --- a/test/personal-server/derived-config.test.ts +++ b/test/personal-server/derived-config.test.ts @@ -9,6 +9,7 @@ import { afterEach, describe, expect, it } from "vitest"; import { applyDerived, derivedConfig, + MCP_GRANT_TTL_SECONDS, // @ts-expect-error - plain ESM module shipped to the server process } from "../../src/personal-server/local/runtime-pkg/derived-config.mjs"; import { ensureRuntime } from "../../src/personal-server/local/runtime.js"; @@ -79,3 +80,19 @@ describe("ensureRuntime", () => { } }); }); + +describe("MCP grant lifetime", () => { + it("is one year, and entry.mjs hands it to the server", () => { + expect(MCP_GRANT_TTL_SECONDS).toBe(365 * 24 * 3600); + const entry = fs.readFileSync( + fileURLToPath( + new URL( + "../../src/personal-server/local/runtime-pkg/entry.mjs", + import.meta.url, + ), + ), + "utf8", + ); + expect(entry).toMatch(/mcpGrantTtlSeconds: MCP_GRANT_TTL_SECONDS/); + }); +}); From 0a767c62c59331a8c4c59e47c7f6af045d8df45b Mon Sep 17 00:00:00 2001 From: Volod Date: Thu, 8 Oct 2026 12:09:25 -0700 Subject: [PATCH 2/2] fix(server): run personal server 1.32.0, which honors mcpGrantTtlSeconds Claude-Session: https://claude.ai/code/session_01Fcv6uEy4zcXaigzDNxeW3j --- src/personal-server/local/config.ts | 2 +- .../local/runtime-pkg/package-lock.json | 40 +++++++++---------- .../local/runtime-pkg/package.json | 4 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/personal-server/local/config.ts b/src/personal-server/local/config.ts index a5cf1e7..b743fc4 100644 --- a/src/personal-server/local/config.ts +++ b/src/personal-server/local/config.ts @@ -58,7 +58,7 @@ export function localServerNetwork(name: VanaNetworkName): LocalServerNetwork { } /** The pinned server release, matching runtime-pkg/package.json. */ -export const PERSONAL_SERVER_VERSION = "1.31.0"; +export const PERSONAL_SERVER_VERSION = "1.32.0"; export function localServerHome(): string { return path.join(getVanaHome(), "cli", "personal-server"); diff --git a/src/personal-server/local/runtime-pkg/package-lock.json b/src/personal-server/local/runtime-pkg/package-lock.json index d62da91..2d37a8c 100644 --- a/src/personal-server/local/runtime-pkg/package-lock.json +++ b/src/personal-server/local/runtime-pkg/package-lock.json @@ -6,8 +6,8 @@ "": { "name": "vana-cli-personal-server-runtime", "dependencies": { - "@opendatalabs/personal-server-ts": "1.31.0", - "@opendatalabs/personal-server-ts-core": "1.31.0" + "@opendatalabs/personal-server-ts": "1.32.0", + "@opendatalabs/personal-server-ts-core": "1.32.0" } }, "node_modules/@adraffy/ens-normalize": { @@ -117,20 +117,20 @@ } }, "node_modules/@opendatalabs/personal-server-ts": { - "version": "1.31.0", - "resolved": "https://registry.npmjs.org/@opendatalabs/personal-server-ts/-/personal-server-ts-1.31.0.tgz", - "integrity": "sha512-Fbx0VuCa1lNILMMbCbLHCvpXER8MAyDCIaeGZ3QDYZfF6AYLj1oVBIiqhjc7vaHfJBmzkIbGR7E8OMWfG1NuYw==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/@opendatalabs/personal-server-ts/-/personal-server-ts-1.32.0.tgz", + "integrity": "sha512-3CE2lR7cisEpASFkrpLzPnHPJapR6J7Wmr5sR2fIBGkyFsIDIUnOMLFX+xomtiH1lkJNV+S32JDi3e2YP4ynDw==", "license": "MIT", "dependencies": { - "@opendatalabs/personal-server-ts-core": "1.31.0", - "@opendatalabs/personal-server-ts-lite": "1.31.0", - "@opendatalabs/personal-server-ts-server": "1.31.0" + "@opendatalabs/personal-server-ts-core": "1.32.0", + "@opendatalabs/personal-server-ts-lite": "1.32.0", + "@opendatalabs/personal-server-ts-server": "1.32.0" } }, "node_modules/@opendatalabs/personal-server-ts-core": { - "version": "1.31.0", - "resolved": "https://registry.npmjs.org/@opendatalabs/personal-server-ts-core/-/personal-server-ts-core-1.31.0.tgz", - "integrity": "sha512-rvf27XMx3bEaQGZD06PHQZgRkpPutNjTvkNm9ZnUQJgerf7MxkrTLwX3+4tg9exuii6zSTtzg/IUV03MlcY+ZA==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/@opendatalabs/personal-server-ts-core/-/personal-server-ts-core-1.32.0.tgz", + "integrity": "sha512-D/3gENV68S2jl3BBiuEv11K0a05SdYNDUfqwCBMXGDvd0s4NG9/1XeHiANltzLAjogPdEZpY74qTyo/t3U5v3w==", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.29.0", @@ -142,26 +142,26 @@ } }, "node_modules/@opendatalabs/personal-server-ts-lite": { - "version": "1.31.0", - "resolved": "https://registry.npmjs.org/@opendatalabs/personal-server-ts-lite/-/personal-server-ts-lite-1.31.0.tgz", - "integrity": "sha512-v8mM/oDslK0poYj+MlFH5fU8HdL+kJUbD6JQWOU93fGMEld+mJlfmkxpzBIHtPU2muZeOj1s13cnIUAk9LXHCQ==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/@opendatalabs/personal-server-ts-lite/-/personal-server-ts-lite-1.32.0.tgz", + "integrity": "sha512-6DIZL9BhbUiudvnjQ4zoXmaMqL/31a4EAHKZ7FVg10maET9IqtliNDk/YJmLfAclVLAF7XyJqAQ2QRqjH92OOQ==", "license": "MIT", "dependencies": { - "@opendatalabs/personal-server-ts-core": "1.31.0", + "@opendatalabs/personal-server-ts-core": "1.32.0", "@opendatalabs/vana-sdk": "3.23.0-pr.211.36da1d8", "node-forge": "^1.4.0", "viem": "^2.54.2" } }, "node_modules/@opendatalabs/personal-server-ts-server": { - "version": "1.31.0", - "resolved": "https://registry.npmjs.org/@opendatalabs/personal-server-ts-server/-/personal-server-ts-server-1.31.0.tgz", - "integrity": "sha512-U9/TuwjOXvzsATdsMjBdewkn/m9/bbZSaX8hGcjhCvBlBFMRGCSymsia1+GAlRMEzpcPsK2sDN62aqP7d61iFw==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/@opendatalabs/personal-server-ts-server/-/personal-server-ts-server-1.32.0.tgz", + "integrity": "sha512-sHJZoO2Irl/PYhaDOm8aNYqP5WcbF7albXGrBYgKfRyVvCPDIwz5wxY2j5iMz1DwfNe7I7NvIcv8CP4apJRX0w==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.17", - "@opendatalabs/personal-server-ts-core": "1.31.0", - "@opendatalabs/personal-server-ts-lite": "1.31.0", + "@opendatalabs/personal-server-ts-core": "1.32.0", + "@opendatalabs/personal-server-ts-lite": "1.32.0", "@opendatalabs/vana-sdk": "3.23.0-pr.211.36da1d8", "better-sqlite3": "^12.11.1", "hono": "^4.13.12", diff --git a/src/personal-server/local/runtime-pkg/package.json b/src/personal-server/local/runtime-pkg/package.json index ac5ea1e..82bc8e2 100644 --- a/src/personal-server/local/runtime-pkg/package.json +++ b/src/personal-server/local/runtime-pkg/package.json @@ -4,8 +4,8 @@ "type": "module", "description": "The Personal Server vana-cli runs on its own. Installed with npm ci from this lockfile so every install is the same.", "dependencies": { - "@opendatalabs/personal-server-ts": "1.31.0", - "@opendatalabs/personal-server-ts-core": "1.31.0" + "@opendatalabs/personal-server-ts": "1.32.0", + "@opendatalabs/personal-server-ts-core": "1.32.0" }, "allowScripts": { "better-sqlite3@12.11.1": true,