Skip to main content
Glama
SabaCan0141

duet-mcp

by SabaCan0141

duet-mcp

English | 日本語

One shared state for humans through a GUI and LLMs through MCP. Define each operation once.

npm CI

Start a project

Requires Node.js 22+.

npx --package=duet-mcp duet init my-app
cd my-app && npm install
npm run dev

Open the URL printed by Vite. Edit text or drag the box; the shared state updates for connected clients. duet init creates the template, build configuration, dependencies, and scripts in an empty directory.

Read template/app.ts for shared state and operations, then template/ui/main.tsx for the screen. Add an action in app.ts and call it from the GUI. Keep the template's rootDir/webDist settings when editing it.

Related MCP server: kcf-mcp

Define an action once

import { defineApp, createAction } from "duet-mcp";
import { guiUrl, awaitChange, observerOps } from "duet-mcp/assets";
import { z } from "zod";

type Doc = { text: string };
const action = createAction<Doc>();

export const app = defineApp({
  id: "notes",
  version: "1.0.0",
  initialDoc: (): Doc => ({ text: "" }),
  actions: {
    set_text: action({
      description: "Replace the shared text.",
      input: z.object({ text: z.string() }),
      handler: ({ doc }, { text }) => {
        doc.update(state => { state.text = text; });
        return { text };
      },
    }),
    gui_url: guiUrl(),
    await_change: awaitChange(),
    ...observerOps(),
  },
});

The handler's document, input, and result are typed. Custom actions and built-in actions share the same actions object.

In the GUI, import useDoc from ../duet/browser, call const doc = useDoc(), and handle the initial null. Then call await doc.set_text({ text: "hello" }). A Node caller imports getDoc from ./duet/node and calls await getDoc() first. MCP takes the same { text: "hello" } input.

For local drafts, import useEdit from duet-mcp/react: begin an edit with edit.begin(doc.text), then submit with edit.submit(text => doc.set_text({ text })). The callback receives the current draft.

Connect an MCP client

Run npm run build, then configure your MCP client to launch node with the absolute path to dist/template/main.js. The template provides GUI URL, observation, screenshot, and blob actions. For screenshots, install Chromium with npx playwright install chromium.

Use npm run typecheck to check your app. Generated template/duet/browser.ts, node.ts, and connection.ts need no manual editing.

State lives in memory; your application owns persistence. For update behavior, observation and guarded edits, assets, and takeover, see doc/SEMANTICS.md.

Available Tools

7 tools
await_changeawait_changeA

省略すると現在の doc と revision を即時取得する。sinceRevision は観測した文字列をそのまま渡す。その版以後のコミットを待ち、既に変更があれば即返す。until は待つ op 名を絞る。全応答に doc が載る。truncated は差分を説明できないという意味。doc を確認すること。再起動や履歴の保持範囲外でも最新 doc を即返す。timedOut の場合も doc と revision を組で読む。changes は対象 op の変更説明で、連続した同じ参加者の同じ op は count にまとまる。activity は最終活動からの経過ミリ秒で、編集完了や優先権は保証しない。activity 自体では起床しない。

ParametersJSON Schema
NameRequiredDescriptionDefault
untilNo待つ op 名。省略すると任意の変更。
timeoutMsNo既定 25000、上限 120000。
sinceRevisionNo直前に観測した revision。省略すると待たずに今の doc を返す。

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It thoroughly explains response guarantees, such as doc appearing in every response, immediate return even outside history retention, timedOut behavior, changes grouping into count, and the non-guarantees around activity and priority. This is far beyond minimal transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and not structured with headings, but nearly every sentence conveys a distinct behavioral or return-value detail that is necessary because no output schema exists. It is front-loaded with the most common use mode, and while a bit wall-of-text-like, it avoids redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given three optional parameters, no output schema, and no annotations, this description does an unusually complete job. It explains return fields, edge cases such as truncated and timedOut, grouping behavior for changes, and the meaning of activity. An agent has enough information to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds important semantic guidance beyond the schema: sinceRevision must be passed as an observed string, omitting it returns the current doc immediately, and until narrows the operations waited on. That extra context justifies a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool waits for commits after a given revision and returns immediately if changes already exist, or fetches the current doc and revision when sinceRevision is omitted. This specific verb-plus-resource behavior clearly separates it from the write-oriented sibling tools like set_text and set_settings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear parameter-driven usage context: omit sinceRevision to get the current state, provide it to wait for subsequent commits, and use until to filter which operations to wait for. It does not explicitly discuss when not to use this tool or name alternatives, but the usage context is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gui_urlgui_urlA

人が操作する GUI の URL を返す。ポートは app.id から導出されるので、人に「どこで開いているか」を聞かれたらこれで答えること。

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the behavioral burden. It discloses that the URL points to the human-operated GUI and that the port is derived from app.id. It does not specify the exact URL format or prerequisites, but for a simple getter this is reasonable.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two compact sentences with no filler. The core fact (returns GUI URL, port from app.id) is front-loaded, and the usage trigger is placed immediately after.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with no output schema and no overlapping siblings, the description covers what it does, how the port is determined, and when to use it. Nothing essential is missing for an agent to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has no parameters, so schema coverage is vacuously 100%. With zero parameters, the description cannot meaningfully add parameter semantics, and the baseline of 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('返す'), a clear resource ('人が操作する GUI の URL'), and a distinct purpose: answering where a human is working. None of the sibling tools (set_text, set_settings, etc.) overlap with URL retrieval, so it is easy for an agent to distinguish.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to use it: when a person asks 'where is it open?'. It also explains that the port is derived from app.id, preventing the agent from guessing or relying on other tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_blobread_blobB

blob を読む。画像なら画像として返す。id は doc から得る。

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

There are no annotations, so the description carries the full behavioral burden. It only discloses that images are returned as images, but does not state what happens for non-image blobs, possible errors, side effects, or the actual return representation. Since no annotation confirms read-only behavior, this is a significant gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description consists of three short Japanese sentences, each addressing a distinct aspect: purpose, return behavior, and parameter source. It is front-loaded, contains no redundant words, and is appropriately sized for a one-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read tool with one parameter, no output schema, and no annotations, the description gives the core purpose, the image return behavior, and the id source. However, it omits non-image return behavior, error handling, and any relationship to sibling tools. With no output schema, the description should more fully explain return values and outcomes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage for the single required 'id' parameter. The description compensates partially by stating that the id is obtained from a doc, which gives the agent a source for the value. However, it does not clarify the format, constraints, or how exactly to extract the id from a doc, so the compensation is incomplete.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('blob を読む', read blob) and a key behavior (if it's an image, return it as an image), which makes the resource and purpose clear. It also notes that the id comes from a doc, adding context. However, it does not explicitly differentiate from sibling tools such as render_screenshot, so it lacks strong sibling distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'id は doc から得る' (id is obtained from doc) implies a prerequisite and a context: the tool should be used when a doc references a blob. This is useful but not explicit about when to choose this over alternatives, and no exclusions or alternative tool mentions are provided. It is implied usage rather than concrete guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_screenshotrender_screenshotA

同じ文書を GUI の別セッションで描画した PNG を返す。人間の下書きやスクロール位置は共有しない。path を渡すとその画面へ移動してから撮る(GUI が解釈する URL をそのまま書く)。

ParametersJSON Schema
NameRequiredDescriptionDefault
pathNo既定 "/"。例: "/board/2?debug=1"

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden and does so well: it discloses that rendering happens in a separate GUI session, that human draft state and scroll position are not shared, and that passing a path navigates before capture. Minor omissions like rendering completion or failure behavior remain, but the core side-effect profile is clear.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences with no filler: the first states the main action, the second warns about state isolation, and the third explains the optional path. All sentences earn their place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with one optional parameter and no output schema, the description is largely complete: it covers output type, state isolation, and path handling. It could mention what happens when path is omitted or how rendering relates to document state, but the essentials are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single optional path parameter, and the description adds value by explaining that the path is a GUI-interpreted URL taken as-is and that providing it moves to that screen before capturing. This goes beyond the schema's default and example.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the exact function: returning a PNG rendered in a separate GUI session for the same document. It clearly distinguishes this from siblings like read_blob or gui_url by focusing on rendering and pixel output rather than data or URL operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context on when the tool should be used (to get a rendered PNG of the document) and explains the path parameter's navigation behavior. It does not explicitly name alternative tools or exclusion cases, but the separate-session and path semantics provide adequate usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_boxset_boxA

Move or resize the box within a 720×480 canvas. The minimum size is 64×64. baseRevision は意図を決めるために観測した revision(文字列)をそのまま渡す。版が変わっていたら handler を実行せず conflict と最新 doc を返す。最新 doc を見て意図を見直すこと。同じ引数を新しい版で自動再送しない。通信エラーは適用結果が不明な場合がある。まず await_change で現在の状態を確認する。

ParametersJSON Schema
NameRequiredDescriptionDefault
xYes
yYes
widthYes
heightYes
baseRevisionYes意図を決めるために観測した revision をそのまま渡す。数値の旧形式は使えない。版が変われば実行前に conflict。

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses conflict behavior, the fact that the handler is not executed on stale versions, the uncertainty caused by communication errors, and the no-retry policy. This is strong behavioral transparency for a mutating tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core operation and size constraint are front-loaded, and every instruction is relevant to correct usage. Some redundancy exists with the baseRevision property description in the schema, and the mixed English/Japanese phrasing slightly reduces readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-output-schema, no-annotation mutation tool with five parameters, the description is unusually complete: operation, constraints, conflict handling, error uncertainty, and a recommended next step. It omits only explicit success-return details and exact coordinate semantics, which are relatively minor.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 20%, so the description compensates by stating canvas bounds and the 64×64 minimum size. baseRevision semantics are explained in detail. It does not explicitly define coordinate origin or maximum x/y/width/height values, but it adds meaningful context beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Move or resize the box within a 720×480 canvas.' This clearly identifies the operation and target, and differentiates it from siblings like set_text and set_settings without ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit procedural guidance: pass the observed revision string, check current state with await_change first, do not auto-resend on a newer revision, and re-evaluate intent against the latest doc. It also states when not to execute the handler, namely when the version has changed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_settingsset_settingsA

Set the canvas heading, notes, visibility, grid, style, color, and opacity. baseRevision は意図を決めるために観測した revision(文字列)をそのまま渡す。版が変わっていたら handler を実行せず conflict と最新 doc を返す。最新 doc を見て意図を見直すこと。同じ引数を新しい版で自動再送しない。通信エラーは適用結果が不明な場合がある。まず await_change で現在の状態を確認する。

ParametersJSON Schema
NameRequiredDescriptionDefault
gridYes
colorYes
notesYes
styleYes
captionYes
opacityYes
visibleYes
baseRevisionYes意図を決めるために観測した revision をそのまま渡す。数値の旧形式は使えない。版が変われば実行前に conflict。

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so well. It discloses conflict behavior (no handler execution, returns latest doc), prohibits automatic retry with the same arguments, warns that communication errors may leave application results unknown, and advises checking state with await_change.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the tool's purpose and then covers the important revision-conflict protocol and error caveats. It is dense and mixes languages, but every sentence conveys a necessary behavioral or procedural fact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 8-parameter mutation tool with no output schema, the description covers conflict semantics, latest-doc review, no-auto-resend behavior, communication-error ambiguity, and the await_change precondition. It does not describe the success return shape or the exact meaning of every visual setting, but it is substantially complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is low at 13%, and the description only restates most parameter names without adding meaning beyond their schema constraints. However, it provides substantial semantics for baseRevision: pass the observed revision string, old numeric formats are invalid, and conflicts occur if the version changed. This partial compensation makes it adequate but incomplete.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific action ('Set') and a specific resource: canvas-level settings including heading, notes, visibility, grid, style, color, and opacity. This distinguishes it from sibling tools like set_text and set_box, which target different resources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear procedural guidance: call await_change first to confirm current state, pass the observed baseRevision, and do not automatically resend with a new revision on conflict. It does not explicitly contrast with sibling tools, but the resource scope and preconditions make the intended usage clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_textset_textA

Replace the shared note text. baseRevision は意図を決めるために観測した revision(文字列)をそのまま渡す。版が変わっていたら handler を実行せず conflict と最新 doc を返す。最新 doc を見て意図を見直すこと。同じ引数を新しい版で自動再送しない。通信エラーは適用結果が不明な場合がある。まず await_change で現在の状態を確認する。

ParametersJSON Schema
NameRequiredDescriptionDefault
textYes
baseRevisionYes意図を決めるために観測した revision をそのまま渡す。数値の旧形式は使えない。版が変われば実行前に conflict。

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and succeeds. It discloses conflict behavior, that the handler is not executed on conflict, that conflict and latest doc are returned, that retry with stale arguments is forbidden, and that communication errors can leave application outcome unknown.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every sentence earns its place. The core action is front-loaded, followed by dense but relevant rules about conflicts, retries, error ambiguity, and preflight checks. There is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers conflict responses, error ambiguity, and precondition checking, which is substantial for a two-parameter tool with no output schema. It stops short of describing the normal success return payload, but the practical call path is fully specified.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 50% because text lacks a property description, but the top-level phrase 'Replace the shared note text' makes the text parameter's meaning clear. baseRevision is thoroughly documented in both the schema and the description, including the requirement to pass the observed revision string exactly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Replace the shared note text', which names the exact verb and resource being acted on. This clearly distinguishes set_text from siblings like set_settings and set_box, so an agent can select the right tool without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit operational guidance: pass the observed baseRevision as-is, do not run the handler on version conflict, re-evaluate intent against the latest doc, never auto-resend stale arguments, and first use await_change to check current state. It even names a sibling tool for the precondition check.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv0.6.1
    • First observedawait_change
    • First observedgui_url
    • First observedread_blob
    • First observedrender_screenshot
    • First observedset_box
    • First observedset_settings
    • First observedset_text

TDQS

A4/5.0

Scored across 7 tools

Disambiguation3/5

set_text and set_settings overlap somewhat because set_settings can update 'notes', which could be confused with the note text set_text replaces. The other tools are clearly distinct, but this boundary ambiguity makes mis-selection possible.

Naming Consistency4/5

Most tools follow a clean verb_noun pattern: set_text, set_settings, set_box, await_change, render_screenshot, and read_blob. gui_url is the outlier and would be clearer as get_gui_url, but the overall convention is still predictable.

Tool Count5/5

Seven tools is well-scoped for this collaborative canvas server. Each tool serves a distinct role: mutating text/settings/box, observing changes, rendering views, and reading blobs.

Completeness4/5

The surface covers the main observe-modify-render workflow: await_change provides current state and revision, set_* tools make changes, and render_screenshot/read_blob provide outputs. Minor gaps exist around explicit create/delete operations for boxes or blob uploads, but they may not be required by the intended domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers