Skip to content

MCP server for Platforma Desktop#1518

Merged
blackcat merged 87 commits intomainfrom
feature/mcp-server
Apr 10, 2026
Merged

MCP server for Platforma Desktop#1518
blackcat merged 87 commits intomainfrom
feature/mcp-server

Conversation

@blackcat
Copy link
Copy Markdown
Contributor

@blackcat blackcat commented Mar 18, 2026

Summary

  • MCP server package (lib/node/pl-mcp-server/) with Streamable HTTP transport
  • Project CRUD tools (list, create, open, close, delete)
  • Block management tools (add, remove, run, stop)
  • Block state tools (get overview, get/set block data)
  • Await tools (await_block_done with two-phase wait)
  • Log tools (get_block_logs from block outputs, get_app_log for Electron log)
  • Screenshot and UI interaction tools (click, type, scroll, press_key, execute_js)
  • Block navigation (select_block, list_available_blocks)
  • Multi-session support (per-client MCP server instances)
  • Lifecycle callbacks for desktop UI sync

Test plan

  • Integration tests: 16 tests covering project CRUD, block management, state read/write, pipeline await, timeout
  • Manual desktop testing: VDJ 003 Tiny Trees project setup via MCP
  • Screenshot verification of all UI operations
  • Block log reading from MiXCR outputs

Greptile Summary

This PR introduces a new @milaboratories/pl-mcp-server package that exposes Platforma Desktop's project/block management capabilities as an MCP (Model Context Protocol) server over Streamable HTTP transport, enabling AI agents to drive the desktop application programmatically. The implementation is well-structured — tools are cleanly separated by domain, the multi-session transport lifecycle is correctly handled (including the race-condition guard added in the latest commit), and the test suite covers the key CRUD/pipeline/state paths with proper setup/teardown.

A few issues were found:

  • data-query.ts — dead pFrame detection condition: lowerPath.endsWith(".pFrame") is applied after toLowerCase(), so the uppercase F ensures the condition is always false. Harmless today because lowerPath.includes("pframe") already covers the common case, but the dead branch is misleading.
  • data-query.ts — O(n²) vectorToJson in query_table: vectorToJson is called once per cell (rows × columns) rather than once per column. At the 1000-row limit with a wide table this materialises the full column array for every single cell, which is wasteful and should be fixed before large tables are queried.
  • logs.ts — silent data loss when shouldUpdateHandle is true: Live log handles can signal that the handle is stale via shouldUpdateHandle. The current code silently omits the entry from results rather than still decoding response.data or surfacing a staleness hint, making log reads silently return nothing for live handles.
  • data-query.ts — identical ternary branches: Two locations use s.type === "column" ? s.spec.name : s.spec.name, which is a no-op ternary likely left from a copy-paste.
  • types.tsgetOpenedProject typed as Promise<any>: This disables TypeScript's checks on all opened-project method calls across the block/state/log/await tools.

Confidence Score: 3/5

  • Safe to merge for initial functionality, but the O(n²) vectorToJson and silent log data loss should be addressed before heavy use against wide or live-log tables.
  • The server transport lifecycle and project/block CRUD tools are solid. The three correctness issues in data-query.ts and logs.ts are real bugs (not just style) — one causes silent data loss for live log handles, one causes quadratic work at the documented 1000-row limit, and one is a dead detection condition — but none affect the core project management or block execution paths covered by the existing tests.
  • lib/node/pl-mcp-server/src/tools/data-query.ts and lib/node/pl-mcp-server/src/tools/logs.ts need the most attention before these tools are used against real data.

Important Files Changed

Filename Overview
lib/node/pl-mcp-server/src/server.ts Core HTTP server with multi-session transport management. The race condition fix (closed-flag guard before transports.set) and top-level error handler are solid. Port retry logic correctly preserves the request handler across recreated servers.
lib/node/pl-mcp-server/src/tools/data-query.ts Three issues: (1) dead condition lowerPath.endsWith(".pFrame") never fires because the path is already lowercased; (2) vectorToJson is called once per cell rather than once per column causing O(n²) work at max 1000-row limit; (3) two ternary branches with identical s.spec.name expressions indicate a likely copy-paste error.
lib/node/pl-mcp-server/src/tools/logs.ts Silent data loss: when shouldUpdateHandle is true, log data available in response.data is discarded and the key is silently omitted from results, giving callers no indication that logs exist but the handle is stale.
lib/node/pl-mcp-server/src/tools/await.ts Two-phase await (overview poll → stable block state) is well-structured. The Promise.race + AbortSignal.timeout + setTimeout triple is slightly redundant but functionally correct.
lib/node/pl-mcp-server/src/tools/types.ts getOpenedProject is typed as Promise<any>, disabling type-checking across all block/state/log/await tools that consume the returned object.
tests/mcp-server/src/with-mcp.ts Clean test harness wrapping MiddleLayer + PlMcpServer lifecycle. Proper cleanup in finally block. getFreePort correctly exported for direct-HTTP tests in server.test.ts.

Comments Outside Diff (3)

  1. lib/node/pl-mcp-server/src/server.ts, line 830-832 (link)

    P1 delete_project uses entry.id instead of entry.rid

    All other project operations (open_project, close_project) call ml.openProject(entry.rid) / ml.closeProject(entry.rid) using the ResourceId. Only delete_project calls ml.deleteProject(entry.id). If entry.id is a different type (e.g., a plain string database identifier rather than the ResourceId), this will pass the wrong argument to deleteProject and likely fail at runtime or silently delete nothing. Compare with the pattern used everywhere else:

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: lib/node/pl-mcp-server/src/server.ts
    Line: 830-832
    
    Comment:
    **`delete_project` uses `entry.id` instead of `entry.rid`**
    
    All other project operations (`open_project`, `close_project`) call `ml.openProject(entry.rid)` / `ml.closeProject(entry.rid)` using the `ResourceId`. Only `delete_project` calls `ml.deleteProject(entry.id)`. If `entry.id` is a different type (e.g., a plain string database identifier rather than the `ResourceId`), this will pass the wrong argument to `deleteProject` and likely fail at runtime or silently delete nothing. Compare with the pattern used everywhere else:
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. lib/node/pl-mcp-server/src/server.ts, line 971-973 (link)

    P2 Missing refreshState before awaiting overview

    list_projects and resolveProject both call ml.projectList.refreshState() before awaiting the value, ensuring fresh data. get_project_overview directly calls project.overview.awaitStableValue() without first triggering a refresh. This may return a stale cached value, especially immediately after mutations (e.g., set_block_data).

    Consider adding a refresh step:

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: lib/node/pl-mcp-server/src/server.ts
    Line: 971-973
    
    Comment:
    **Missing `refreshState` before awaiting overview**
    
    `list_projects` and `resolveProject` both call `ml.projectList.refreshState()` before awaiting the value, ensuring fresh data. `get_project_overview` directly calls `project.overview.awaitStableValue()` without first triggering a refresh. This may return a stale cached value, especially immediately after mutations (e.g., `set_block_data`).
    
    Consider adding a refresh step:
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
  3. lib/node/pl-mcp-server/src/server.ts, line 1009-1060 (link)

    P2 await_block_done does not handle all terminal error states

    The polling loop only checks for "Done" and "Limbo" as terminal states. If there are other terminal/error states in the Platforma calculation status enum (e.g., "RunningError", "Failed", or any future additions), the loop will keep polling until the full timeout elapses rather than returning immediately with the error condition.

    This is a usability issue — an AI agent waiting for a failed block will silently wait the full timeout (default 2 minutes) instead of being told immediately that the block failed. Consider exhaustively listing all non-Running states that should short-circuit the loop, or inverting the check to only continue looping on explicitly "Running" / "NotCalculated" states.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: lib/node/pl-mcp-server/src/server.ts
    Line: 1009-1060
    
    Comment:
    **`await_block_done` does not handle all terminal error states**
    
    The polling loop only checks for `"Done"` and `"Limbo"` as terminal states. If there are other terminal/error states in the Platforma calculation status enum (e.g., `"RunningError"`, `"Failed"`, or any future additions), the loop will keep polling until the full `timeout` elapses rather than returning immediately with the error condition.
    
    This is a usability issue — an AI agent waiting for a failed block will silently wait the full timeout (default 2 minutes) instead of being told immediately that the block failed. Consider exhaustively listing all non-`Running` states that should short-circuit the loop, or inverting the check to only continue looping on explicitly `"Running"` / `"NotCalculated"` states.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: lib/node/pl-mcp-server/src/tools/data-query.ts
Line: 30-32

Comment:
**Dead condition — `.endsWith(".pFrame")` never matches after `toLowerCase()`**

`lowerPath` is already fully lowercased, so `lowerPath.endsWith(".pFrame")` (capital `F`) will always evaluate to `false`. Any handle located at a path that would match only the second condition (but not the `includes("pframe")` first condition) will be silently misclassified as a pTable or not detected at all.

```suggestion
      if (lowerPath.includes("pframe") || lowerPath.endsWith(".pframe")) {
```
(or simply remove the dead second condition, since `lowerPath.includes("pframe")` already subsumes `.endsWith(".pframe")`)

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/node/pl-mcp-server/src/tools/data-query.ts
Line: 235-244

Comment:
**O(n²) performance: `vectorToJson` called once per cell instead of once per column**

`vectorToJson(vectors[c], actualRows)` is invoked inside the inner loop — once for every row `r` and every column `c`. Each call allocates and fills an array of `actualRows` elements, only to immediately index into it with `[r]`. For the maximum `limit` of 1000 rows and e.g. 20 columns, this means 20,000 `vectorToJson` invocations each scanning 1000 entries = 20 million iterations of the bit-mask logic instead of 20,000.

Materialise each column vector once outside the row loop:

```typescript
// Pre-materialise all column vectors once
const columnVectors = vectors.map((v) => vectorToJson(v, actualRows));

const rows: unknown[][] = [];
for (let r = 0; r < actualRows; r++) {
  const row: unknown[] = columnVectors.map((col) => col[r]);
  rows.push(row);
}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/node/pl-mcp-server/src/tools/logs.ts
Line: 46-51

Comment:
**Silent data loss when `shouldUpdateHandle` is `true`**

When `shouldUpdateHandle` is `true` (the driver signalling that the handle is stale and a fresh one is available in `response.newHandle`), the log content is available in `response.data` but the code silently discards it and writes nothing into `results[key]`. The caller receives an empty object `{}` with no indication that logs exist but the handle was just stale.

At a minimum, fall through to decode the data even when the handle should be refreshed, or surface a placeholder that tells the caller the handle needs updating:

```typescript
const response = await logDriver.lastLines(handle, lines);
results[key] = new TextDecoder().decode(response.data);
// Optionally surface handle staleness so callers can refresh
if (response.shouldUpdateHandle) {
  results[`${key}:handleStale`] = true as unknown as string;
}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/node/pl-mcp-server/src/tools/data-query.ts
Line: 161-162

Comment:
**Identical ternary branches — `name` field is always `s.spec.name`**

Both branches of the conditional are identical, so the ternary is dead code. This pattern appears in two places (`get_block_outputs` and `query_table`). The likely intent was to access a different property for the axis-key spec type (e.g. `s.spec.columnId` or similar).

```suggestion
              name: s.spec.name,
```

The same issue exists at the `query_table` column-headers section (line ~271).

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/node/pl-mcp-server/src/tools/types.ts
Line: 14

Comment:
**`getOpenedProject` return type is `any` — loses type safety**

`getOpenedProject` is typed as returning `Promise<any>`, which propagates `any` into every tool that calls it (all block/state/log/await tools). This disables TypeScript's checks on the project object's methods and properties (e.g. `project.mutateBlockStorage`, `project.getBlockState`, `project.overview`, etc.).

Consider typing it as the concrete opened-project type exported by `pl-middle-layer`:

```typescript
getOpenedProject: (projectId: string) => Promise<OpenedProject>;
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix: address PR review comments" | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 18, 2026

🦋 Changeset detected

Latest commit: ef258fa

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@milaboratories/pl-mcp-server Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request establishes a new Model Context Protocol (MCP) server, enabling robust programmatic interaction with the Platforma Desktop application. It introduces a suite of tools that allow external clients, such as AI assistants, to seamlessly manage projects, control block execution, access internal states, retrieve logs, and directly manipulate the desktop user interface. This enhancement significantly boosts the automation capabilities and extensibility of the Platforma Desktop platform.

Highlights

  • New MCP Server Package: Introduced lib/node/pl-mcp-server/ to provide a Model Context Protocol (MCP) server for Platforma Desktop, enabling programmatic interaction.
  • Streamable HTTP Transport: Implemented MCP communication over Streamable HTTP, binding to 127.0.0.1 with secret and origin validation for secure local access.
  • Project Management Tools: Added a comprehensive set of tools for listing, creating, opening, closing, and deleting projects within the Platforma environment.
  • Block Management Tools: Included tools for adding, removing, running, and stopping blocks, along with functionalities to list available blocks and navigate the UI to specific blocks.
  • Block State Interaction: Provided tools to retrieve a project's overview, get the current state of a block, and set user-facing data for blocks.
  • Pipeline Await Functionality: Developed await_block_done for a two-phase waiting mechanism that ensures a block completes its computation and its outputs stabilize before proceeding.
  • Logging Capabilities: Added tools to retrieve block-specific execution logs (get_block_logs) and application-level logs (get_app_log) for debugging and monitoring.
  • UI Interaction Tools: Implemented desktop-specific tools for capturing screenshots, simulating mouse clicks, typing text, pressing keyboard keys, scrolling, and executing arbitrary JavaScript in the renderer process.
  • Multi-Session Support: The server is designed to support multiple client sessions, with each client receiving its own isolated MCP server instance.
  • Comprehensive Test Suite: A new tests/mcp-server/ package was added with extensive integration tests covering all implemented MCP tools to ensure functionality and stability.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive MCP server for Platforma Desktop, including a new package pl-mcp-server, extensive integration tests, and detailed implementation documentation. The changes are well-structured and cover a wide range of functionalities from project and block management to UI interaction. My review focuses on improving robustness, correctness in edge cases, and configuration accuracy. I've identified a potential build issue in package.json and a few areas in the server implementation where error handling and Unicode support could be enhanced.

Comment thread lib/node/pl-mcp-server/package.json Outdated
Comment thread lib/node/pl-mcp-server/src/server.ts Outdated
Comment thread lib/node/pl-mcp-server/src/server.ts Outdated
Comment thread lib/node/pl-mcp-server/src/server.ts Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.08%. Comparing base (bf48d44) to head (ef258fa).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1518      +/-   ##
==========================================
- Coverage   54.14%   54.08%   -0.06%     
==========================================
  Files         254      254              
  Lines       14567    14567              
  Branches     3028     3028              
==========================================
- Hits         7887     7879       -8     
- Misses       5663     5676      +13     
+ Partials     1017     1012       -5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vgpopov
Copy link
Copy Markdown
Contributor

vgpopov commented Mar 18, 2026

@greptileai

Comment thread lib/node/pl-mcp-server/src/server.ts Outdated
Comment thread lib/node/pl-mcp-server/src/server.ts Outdated
Comment thread tests/mcp-server/src/server.test.ts
@blackcat blackcat marked this pull request as draft March 18, 2026 19:30
Comment thread lib/node/pl-mcp-server/src/index.ts Outdated
Comment thread lib/node/pl-mcp-server/src/server.ts
Comment thread lib/node/pl-mcp-server/src/server.ts Outdated
Comment thread lib/node/pl-mcp-server/src/server.ts Outdated
Comment thread lib/node/pl-mcp-server/src/server.ts Outdated
> "implement step 1 and commit"

- New package @milaboratories/pl-mcp-server in lib/node/pl-mcp-server/
- PlMcpServer class: Streamable HTTP transport on localhost:{port}/{secret}/mcp
- Secret path validation (404 for wrong paths), Origin header validation
- Dummy ping tool proving end-to-end MCP connectivity
- Integration test package in tests/mcp-server/ with withMcpServer helper
- Tests: ping tool, tool listing, wrong secret 404, wrong path 404
- Added @modelcontextprotocol/sdk to workspace catalog
…mpat

"fix MCP server tests failing due to zod version incompatibility"

SDK v1.27.1 requires zod@^3.25 (imports zod/v3 subpath), but workspace
pins zod@~3.23.8. Downgraded to v1.22.0 (last version with zod@^3.23.8
as regular dep). Added zod-to-json-schema@~3.24.1 override to prevent
transitive dep from resolving to 3.25.x.
…mpat

"upgrade zod instead of downgrading MCP SDK"

Reverts SDK downgrade from previous commit. Upgrades zod from ~3.23.8
to ~3.25.76 which provides the /v3 subpath export required by MCP SDK
v1.27.1. Removes zod-to-json-schema override. Full project build and
type check passes (165/165 tasks).
"avoid version mismatch when used in desktop app"

Desktop app has its own pl-middle-layer version. Using peer dep
ensures the MCP server uses the host's version, avoiding
incompatible private property declarations in TypeScript.
"fix type check failure in mcp-server-tests"

pnpm doesn't resolve peer deps to workspace packages automatically.
Adding pl-middle-layer as both peer dep (for external consumers)
and dev dep (workspace:* for monorepo) ensures TypeScript sees
a single MiddleLayer type.
"fix session rejection when Claude Code reconnects"

Single-transport design bound to one session — reconnecting clients
were rejected. Now creates a new McpServer+transport per session,
tracked by session ID. Each client gets its own session. Transports
are cleaned up on close.
"implement step 3: project management tools for MCP server"

Adds 5 project management tools to the MCP server:
- list_projects: lists all projects with IDs, labels, status
- create_project: creates a new project, returns projectId
- open_project: opens a project for editing
- close_project: closes an opened project
- delete_project: permanently deletes a project

Uses resourceIdToString for project IDs consistent with desktop app.
All tools use Zod input schema validation via MCP SDK.
Integration tests cover full lifecycle and multi-project scenarios.
"wire project lifecycle events to desktop app UI"

Added PlMcpServerCallbacks interface with onProjectCreated,
onProjectOpened, onProjectClosed, onProjectDeleted hooks.
Desktop app wires these to worker events that refresh the
project list and navigate the UI when MCP tools modify projects.
"enable AI assistants to see the desktop app screen"

Adds captureScreenshot callback to PlMcpServerCallbacks and
a capture_screenshot MCP tool that returns the current window
as a base64 PNG image. Desktop app wires this via
invokeParentMethod → webContents.capturePage().
"implement step 4: block management tools for MCP server"

Adds 4 block management tools:
- add_block: add a block from registry (from-registry-v2) or local dev (dev-v2)
- remove_block: delete a block from a project
- run_block: start block execution (auto-starts stale upstreams)
- stop_block: stop a running block

Uses getOpenedProject helper to resolve projectId → Project.
Integration tests cover add/remove lifecycle and tool listing.
"implement step 5: block state read/write tools for MCP server"

Adds 3 block state tools:
- get_project_overview: returns all blocks with status, canRun, stale, errors
- get_block_state: returns block's user data (__data) and outputs
- set_block_data: updates block data via mutateBlockStorage (triggers args derivation)

Integration tests verify overview retrieval, data roundtrip (set → get).
"enable AI assistants to interact with desktop app UI directly"

Adds 5 UI interaction tools via Electron's sendInputEvent and
executeJavaScript APIs:
- click: click at x,y coordinates (single or double)
- type_text: type text into focused element
- press_key: press keyboard keys with optional modifiers
- scroll: scroll at a given position
- execute_js: run JavaScript in renderer for DOM queries
"document coordinate scaling, execute_js pattern, and hybrid testing workflow"

Covers the critical coordinate system issue (device pixels vs CSS pixels),
the getBoundingClientRect pattern for precise element targeting, and the
practical workflow for testing real bioinformatics blocks via UI tools.
"list blocks from configured registries with optional name filter"
"navigate desktop UI to display a specific block"
"simplify Step 6: two-phase wait in one tool"
"add answers to all 5 open questions"
@blackcat blackcat enabled auto-merge April 9, 2026 15:51
@blackcat blackcat requested a review from vadimpiven April 9, 2026 15:52
Comment thread lib/model/common/src/drivers/log.ts
Comment thread lib/node/pl-mcp-server/src/tools/data-query.ts Outdated
Comment thread lib/node/pl-mcp-server/src/tools/data-query.ts Outdated
Comment thread lib/node/pl-mcp-server/src/tools/data-query.ts Outdated
Comment thread tests/mcp-server/src/with-mcp.ts
Comment thread lib/model/common/src/drivers/log.ts Outdated
Comment on lines +8 to +12
export type LiveLogHandle = `${typeof LIVE_LOG_PREFIX}${string}`;

/** Handle of the ready logs of a program. */
export type ReadyLogHandle = `log+ready://log/${string}`;
export type ReadyLogHandle = `${typeof READY_LOG_PREFIX}${string}`;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

brand this types

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 657affe

Comment on lines +40 to +41
const overview = await project.overview.getValue();
if (!overview) continue;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure that we don't add some delay?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 657affe

import type { PlMcpServerCallbacks } from "../server";

export interface AuthorMarker {
authorId: string;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

brand it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 657affe

Comment thread lib/node/pl-mcp-server/src/tools/types.ts Outdated
* Returns token estimate, or a string like ">1234 (truncated at 10000 nodes)"
* if the object graph is too large to fully traverse.
*/
export function estimateTokens(value: unknown, nodeLimit = NODE_LIMIT): number | string {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why types.ts include some logic?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 657affe

* Returns token estimate, or a string like ">1234 (truncated at 10000 nodes)"
* if the object graph is too large to fully traverse.
*/
export function estimateTokens(value: unknown, nodeLimit = NODE_LIMIT): number | string {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's test functions with more or less complex logic

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 657affe

context: Record<string, unknown>,
timeout: number,
): unknown {
return runInNewContext(`(${expression})`, context, {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain this concern? what do you want to achieve?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to move this to the QuickJS VM. Thank you!
Fixed in ef258fa

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block data could be huge, no HUGE. We don't want to load full json into the context. Thats why we have transform argument. It allows claude inject JS to query exact data.

This https://github.com/milaboratory/platforma/blob/feature/mcp-server/lib/node/pl-mcp-server/src/tools/block-state.ts#L43 will help you.

…Json

- Rename isAnyLogHandle → isLogHandle (drop "Any" from new names)
- Call getSpec before getShape (getShape triggers join calculation)
- Simplify vectorToJson: push pTableValue() directly, no if-else
- Add requiresCreatePTable: 2 to test MiddleLayer capabilities
organization: string,
name: string,
version: string,
) => Promise<unknown>;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really unknown?

login?: string;
}>;
/** Disconnect from current server. */
disconnect?: () => Promise<void>;
Copy link
Copy Markdown
Collaborator

@AStaroverov AStaroverov Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean onDisconnect ?

}

/** Set or update the MiddleLayer instance (e.g. after connecting to a server). */
setMiddleLayer(ml: MiddleLayer | null | undefined) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need this method? mb better have readonly ml?

this.ml = ml ?? null;
}

get url(): string {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getUrl

…kens logic

- Brand LiveLogHandle/ReadyLogHandle with Branded<> (#2)
- Add 500ms minimum delay between polls in await_block_done (#3)
- Remove duplicate AuthorMarker, import from pl-middle-layer (#4)
- Move estimateTokens/summarizeOutputs from types.ts to tokens.ts (#6)
- Tests already exist and pass from tokens.ts (#7)
node:vm is not a security sandbox — expressions can escape and access
Node APIs. QuickJS (via quickjs-emscripten, already in the monorepo)
runs in a WASM sandbox with no access to Node APIs, filesystem, or
process. Memory limited to 16MB, execution interrupted via deadline.

Data is marshaled via JSON in/out. safeEval is now async (QuickJS
init is lazy). Shared runtime across evaluations, fresh context per call.
Moved safeEval from types.ts to sandbox.ts.
@blackcat blackcat added this pull request to the merge queue Apr 10, 2026
Merged via the queue into main with commit 9b62f34 Apr 10, 2026
31 of 33 checks passed
@blackcat blackcat deleted the feature/mcp-server branch April 10, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants