Tools
Expose plain MCP tools without a UI
Eney extensions are MCP servers. In addition to (or instead of) widgets, you can register plain MCP tools — functions that return text or JSON directly to Eney without rendering a UI.
You can find more details in the official MCP documentation.
Registering a plain tool
Use server.tool() on the McpServer instance:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer(
{ name: "my-extension", version: "1.0.0" },
{ capabilities: { logging: {}, resources: {} } },
);
server.tool(
"get-system-info",
"Returns basic system information",
{
detail: z.enum(["basic", "full"]).optional().describe("Level of detail"),
},
async ({ detail }) => {
const info = detail === "full"
? { platform: process.platform, arch: process.arch, node: process.version }
: { platform: process.platform };
return {
content: [{ type: "text", text: JSON.stringify(info, null, 2) }],
};
},
);Mixed extension (tools + widgets)
You can register both plain tools and widgets in the same extension. First, create your server and call setupUIXForMCP. Then, use both server.tool() and uixServer.registerWidget():
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { setupUIXForMCP } from "@eney/api";
import { z } from "zod";
import MyWidget from "./components/my-widget.js";
const server = new McpServer(
{ name: "my-extension", version: "1.0.0" },
{ capabilities: { logging: {}, resources: {} } },
);
// Plain tool — returns text
server.tool(
"summarize-file",
"Returns a plain-text summary of a file",
{ path: z.string().describe("Absolute path to the file") },
async ({ path }) => {
// read and summarize...
return { content: [{ type: "text", text: "Summary: ..." }] };
},
);
// Widget — renders native UI in Eney
const uixServer = setupUIXForMCP(server);
uixServer.registerWidget(MyWidget);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);Both plain tools and widgets appear in the tool list. When a widget is triggered, Eney intercepts the call to render its UI instead of returning a text response.