@ohmymcp/pi-directx
The MCP-Direct bridge for Pi: turn any MCP server into native Pi tools — createMCPBridge + registerToolsFromMCP + jsonSchemaToTypeBox + sanitizeParams. Reuse when building any Pi MCP-direct extension.
Package details
Install @ohmymcp/pi-directx from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@ohmymcp/pi-directx- Package
@ohmymcp/pi-directx- Version
0.1.0- Published
- Aug 5, 2026
- Downloads
- 144/mo · 21/wk
- Author
- ev3lynx
- License
- unknown
- Types
- extension
- Size
- 27.5 KB
- Dependencies
- 1 dependency · 0 peers
Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@ohmymcp/pi-directx
The MCP-Direct bridge for Pi — turn any MCP server into native Pi tools. One shared module for building MCP-direct extensions: no
pi-mcp-adapter, no duplicated glue.
pi-directx materializes the proven MCP-Direct pattern (spawn server → JSON-RPC 2.0 stdio handshake → tools/list → registerTool each tool) into a small, typed, reusable library. It was extracted from ~1,250 lines of near-identical code that lived inline in 5 Pi extensions (devctx, everything, exa, firecrawl-mcp, sequential-thinking) — they now all ride on this module.
Install
npm install @ohmymcp/pi-directx
# or as a Pi package source:
pi install npm:@ohmymcp/pi-directx@0.1.0
Usage — a full MCP-direct extension in ~25 lines
// extensions/my-server.ts
import { createMCPBridge, registerToolsFromMCP } from '@ohmymcp/pi-directx';
export default function (pi: any) {
const bridge = createMCPBridge('my-mcp-server', {
env: { ...process.env },
onLog: (l) => pi.logger?.info(`[MyServer] ${l}`),
onError: (e) => pi.logger?.error(`[MyServer] ${e}`),
});
registerToolsFromMCP(pi, {
bridge,
label: 'MyServer',
prefix: 'myserver_', // optional tool-name prefix
steeringTools: ['myserver_orient', 'myserver_connect'], // attach promptGuidelines
guidelines: ['Session start: use these tools first.'],
});
pi.on('session_shutdown', () => bridge.close());
}
API
| Export | Signature | What it does |
|---|---|---|
createMCPBridge |
(cmd: string, opts?: MCPBridgeOptions) => MCPBridge |
Spawns the server; owns JSON-RPC 2.0 request routing (requestId, 30s timeout, exit cleanup). bridge.call(method, params) sends a request and resolves the result. |
registerToolsFromMCP |
(pi: any, opts: RegisterToolsOptions) => Promise<{initialized, tools}> |
initialize → tools/list → registerTool for every discovered tool. Encapsulates schema conversion, param sanitization, promptSnippet (REQUIRED for tool visibility in Pi) and optional steering. |
jsonSchemaToTypeBox |
(jsonSchema: any) => TSchema |
Converts MCP JSON Schema → Pi's TypeBox schema (enums, optionals, nested objects). |
sanitizeParams |
(params: any, jsonSchema: any) => any |
Reconciles string-typed LLM params against the schema (string→boolean/number) before forwarding. |
createMCPBridge options
interface MCPBridgeOptions {
args?: string[]; // e.g. ['-y', '@scope/server']
env?: typeof process.env;
cwd?: string;
timeoutMs?: number; // default 30000
onLog?: (line: string) => void; // non-JSON stdout + stderr
onError?: (message: string) => void;
onExit?: (code: number | null) => void;
}
registerToolsFromMCP options
interface RegisterToolsOptions {
bridge: MCPBridge;
label?: string; // UI label prefix, e.g. 'Devctx'
prefix?: string; // tool-name prefix, e.g. 'everything_'
clientName?: string; // clientInfo.name for initialize
clientVersion?: string;
protocolVersion?: string; // default '2024-11-05'
steeringTools?: string[]; // tools that get promptGuidelines
guidelines?: string[]; // steering bullets
onRegistered?: (toolName: string) => void;
}
Why the key contracts matter
promptSnippetis REQUIRED — Pi omits custom tools from the "Available tools" system-prompt section without it; the agent would never learn the tools exist.registerToolsFromMCPattaches it automatically.promptGuidelinessteering — attach guidance to session-start tools only, so it appears once instead of N× duplicating in the system prompt.sanitizeParams— LLMs pass booleans/numbers as strings; reconcile against the JSON schema before the server sees them.- 30s timeout — a hung server rejects + cleans up pending requests instead of leaking.
Development
npm install
npm run build # tsc → dist/ (mcp-direct.js + .d.ts)
npm run smoke # spawns devctx-mcp, asserts 30 tools / snippets / steering / live call
License
MIT