Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/pdf-server/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
cliLocalFiles,
DEFAULT_PDF,
allowedLocalDirs,
cliLocalDirs,
writeFlags,
} from "./server.js";

Expand Down Expand Up @@ -162,6 +163,7 @@ async function main() {
console.error(`[pdf-server] Registered local file: ${filePath}`);
} else if (s.isDirectory()) {
allowedLocalDirs.add(filePath);
cliLocalDirs.add(filePath);
console.error(`[pdf-server] Registered local directory: ${filePath}`);
}
} else {
Expand Down
26 changes: 26 additions & 0 deletions examples/pdf-server/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
startFileWatch,
stopFileWatch,
cliLocalFiles,
cliLocalDirs,
isWritablePath,
writeFlags,
viewSourcePaths,
Expand Down Expand Up @@ -786,6 +787,31 @@ describe("createServer useClientRoots option", () => {
expect(server.server.oninitialized).toBeFunction();
server.close();
});

it("preserves CLI directories when the client returns no roots", async () => {
const cliDir = "/cli/documents";
const previousClientDir = "/client/documents";
cliLocalDirs.add(cliDir);
allowedLocalDirs.add(cliDir);
allowedLocalDirs.add(previousClientDir);

const server = createServer({ useClientRoots: true });
try {
spyOn(server.server, "getClientCapabilities").mockReturnValue({
roots: {},
});
spyOn(server.server, "listRoots").mockResolvedValue({ roots: [] });

await server.server.oninitialized?.();

expect(allowedLocalDirs).toEqual(new Set([cliDir]));
} finally {
allowedLocalDirs.delete(cliDir);
allowedLocalDirs.delete(previousClientDir);
cliLocalDirs.delete(cliDir);
await server.close();
}
});
});

describe("isWritablePath", () => {
Expand Down
8 changes: 6 additions & 2 deletions examples/pdf-server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ export const allowedLocalDirs = new Set<string>();
*/
export const cliLocalFiles = new Set<string>();

/** Directory paths explicitly passed as CLI args. */
export const cliLocalDirs = new Set<string>();

/**
* Write-permission flags. Object wrapper (not a bare `let`) so main.ts can
* mutate via the exported binding without re-import gymnastics — same
Expand Down Expand Up @@ -954,6 +957,7 @@ async function refreshRoots(server: Server): Promise<void> {
try {
const { roots } = await server.listRoots();
allowedLocalDirs.clear();
for (const dir of cliLocalDirs) allowedLocalDirs.add(dir);
for (const root of roots) {
if (isFileUrl(root.uri)) {
const dir = fileUrlToPath(root.uri);
Expand Down Expand Up @@ -1275,8 +1279,8 @@ export function createServer(options: CreateServerOptions = {}): McpServer {

if (useClientRoots) {
// Fetch roots on initialization and subscribe to changes
server.server.oninitialized = () => {
refreshRoots(server.server);
server.server.oninitialized = async () => {
await refreshRoots(server.server);
};
server.server.setNotificationHandler(
"notifications/roots/list_changed",
Expand Down