MCP server and browser bridge primitives for askable UI context.
This package turns askable's semantic UI context into MCP-friendly resources and tools.
Instead of relying on generic browser scraping, screenshot OCR, or DOM reconstruction, askable-mcp exposes the app-authored meaning of the UI:
- current focus (
ui_context) - recent interaction history (
ui_history) - visible annotated elements (
ui_viewport) - a command channel for explicit focus actions (
select_element)
Generic browser MCP servers help agents inspect or control web pages.
askable-mcp is a different layer:
- browser MCP reconstructs meaning from DOM/layout/screenshots
- askable-mcp exposes semantic context the app already knows
Example:
{
"metric": "revenue",
"delta": "-12%",
"period": "Q3",
"screen": "RevenueScreen"
}That makes the MCP surface much higher-signal for copilots, IDE agents, and desktop AI tools.
This repo currently ships:
createAskableMcpSnapshot()— serialize anAskableContextinto an MCP-friendly session snapshotcreateAskableMcpBridge()— send snapshot updates through an injected transportAskableMcpServer— in-memory session/resource/tool statecreateAskableMcpSdkServer()— MCP SDK adapter exposing askable resources and theselect_elementtoolaskable-mcpCLI — runnable stdio MCP server with a local bridge HTTP sidecar
npm install @askable-ui/mcp @askable-ui/corenpm run build
npm run startBy default this starts:
- an MCP stdio server on
stdin/stdoutfor Claude Desktop, Cursor, or other process-spawned MCP clients - a local bridge server on
http://127.0.0.1:4318
Available local bridge endpoints:
POST /bridge— ingest serialized snapshot messages from the browser/app bridgeGET /sessions— inspect known askable sessionsGET /commands?sessionId=...— drain queuedselect_elementcommands for a browser sessionGET /health— basic health check
You can change the bridge listener with CLI flags:
node dist/cli.js --host 127.0.0.1 --bridge-port 4318Build the package, then point Claude Desktop at the stdio entrypoint:
{
"mcpServers": {
"askable": {
"command": "node",
"args": [
"/absolute/path/to/askable-mcp/dist/cli.js",
"--bridge-port",
"4318"
]
}
}
}After Claude Desktop launches the server, ui_context, ui_history, ui_viewport, and select_element become available once your app starts posting snapshots to the local bridge.
import { createAskableContext } from '@askable-ui/core';
import { createAskableMcpBridge } from '@askable-ui/mcp';
const ctx = createAskableContext({ viewport: true });
const sessionId = 'dashboard-tab';
createAskableMcpBridge({
ctx,
sessionId,
pageUrl: window.location.href,
pageTitle: document.title,
includeViewport: true,
transport: {
send(message) {
void fetch('http://127.0.0.1:4318/bridge', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: message,
});
},
},
});
async function pollCommands() {
const response = await fetch(
`http://127.0.0.1:4318/commands?sessionId=${encodeURIComponent(sessionId)}`
);
const payload = (await response.json()) as {
commands: Array<{ type: 'select_element'; elementId: string }>;
};
for (const command of payload.commands) {
if (command.type === 'select_element') {
console.log('focus element in app', command.elementId);
}
}
}
setInterval(() => {
void pollCommands();
}, 500);import { createAskableContext } from '@askable-ui/core';
import {
AskableMcpServer,
createAskableMcpBridge,
createAskableMcpSdkServer,
} from '@askable-ui/mcp';
const ctx = createAskableContext({ viewport: true });
const state = new AskableMcpServer({
onCommand(command) {
console.log('bridge command', command);
},
});
createAskableMcpBridge({
ctx,
sessionId: 'dashboard-tab',
pageUrl: 'https://app.example.com/revenue',
pageTitle: 'Revenue dashboard',
includeViewport: true,
transport: {
send(message) {
state.ingestBridgeMessage(message);
},
},
});
const mcpServer = createAskableMcpSdkServer(state, {
name: 'askable-mcp',
version: '0.1.0',
});- browser-side helpers for handling
select_elementautomatically - streamable HTTP deployment story
- multi-session routing and active-session selection UX
- richer Claude Desktop / Cursor setup docs
- optional auth / origin controls for the local bridge endpoint
npm install
npm test
npm run build