#!/usr/bin/env node
/**
* Oranguru MCP Server
* Provides documentation and code generation for Oranguru components
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListResourcesRequestSchema,
ListToolsRequestSchema,
ReadResourceRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Component documentation data
const COMPONENTS = {
Boxer: {
component: 'Boxer',
description: 'Advanced combobox/select with virtualization and server-side data support',
examples: {
basic: `import { Boxer } from '@warkypublic/oranguru';
import { useState } from 'react';
const sampleData = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Cherry', value: 'cherry' }
];
function MyComponent() {
const [value, setValue] = useState(null);
return (
);
}`,
multiSelect: `import { Boxer } from '@warkypublic/oranguru';
import { useState } from 'react';
function MultiSelectExample() {
const [values, setValues] = useState([]);
return (
);
}`,
server: `import { Boxer } from '@warkypublic/oranguru';
function ServerSideExample() {
const [value, setValue] = useState(null);
const handleAPICall = async ({ page, pageSize, search }) => {
const response = await fetch(\`/api/items?page=\${page}&size=\${pageSize}&search=\${search}\`);
const result = await response.json();
return {
data: result.items,
total: result.total
};
};
return (
);
}`
},
exports: ['Boxer', 'BoxerProvider', 'useBoxerStore'],
hook: 'useBoxerStore()',
name: 'Boxer',
provider: 'BoxerProvider'
},
ErrorBoundary: {
components: ['ReactErrorBoundary', 'ReactBasicErrorBoundary'],
description: 'React error boundary components for graceful error handling',
examples: {
basic: `import { ReactBasicErrorBoundary } from '@warkypublic/oranguru';
function App() {
return (
);
}`,
full: `import { ReactErrorBoundary } from '@warkypublic/oranguru';
function App() {
const handleReportError = () => {
console.log('Report error to support');
};
const handleReset = () => {
console.log('Reset application state');
window.location.reload();
};
const handleRetry = () => {
console.log('Retry failed operation');
};
return (
);
}`,
nested: `import { ReactErrorBoundary } from '@warkypublic/oranguru';
// Multiple error boundaries for granular error handling
function App() {
return (
);
}`,
globalConfig: `import { SetErrorBoundaryOptions } from '@warkypublic/oranguru';
// Configure error boundary globally
SetErrorBoundaryOptions({
disabled: false, // Set to true to pass through errors (dev mode)
onError: (error, errorInfo) => {
console.error('Global error handler:', error);
// Send to analytics service
analytics.trackError(error, errorInfo);
}
});`
},
exports: ['ReactErrorBoundary', 'ReactBasicErrorBoundary', 'SetErrorBoundaryOptions', 'GetErrorBoundaryOptions'],
name: 'ErrorBoundary'
},
Former: {
component: 'Former',
description: 'Form component with React Hook Form integration and validation',
examples: {
basic: `import { Former } from '@warkypublic/oranguru';
import { useRef } from 'react';
import { Controller } from 'react-hook-form';
function BasicForm() {
const formRef = useRef(null);
return (
{
console.log('Saving:', data);
await fetch('/api/save', {
method: 'POST',
body: JSON.stringify(data)
});
}}
>
(
)}
rules={{ required: 'Name is required' }}
/>
(
)}
rules={{ required: 'Email is required' }}
/>
);
}`,
withWrapper: `import { Former, FormerModel } from '@warkypublic/oranguru';
import { useState } from 'react';
function ModalForm() {
const [opened, setOpened] = useState(false);
return (
<>
setOpened(false)}
>
}
/>
>
);
}`,
withAPI: `import { Former, FormerRestHeadSpecAPI } from '@warkypublic/oranguru';
function APIForm() {
return (
{/* Form fields */}
);
}`,
customLayout: `import { Former } from '@warkypublic/oranguru';
function CustomLayoutForm() {
return (
{/* Form fields */}
);
}`,
refMethods: `import { Former } from '@warkypublic/oranguru';
import { useRef } from 'react';
function FormWithRef() {
const formRef = useRef(null);
const handleValidate = async () => {
const isValid = await formRef.current?.validate();
console.log('Form valid:', isValid);
};
const handleSave = async () => {
const result = await formRef.current?.save();
console.log('Save result:', result);
};
const handleReset = () => {
formRef.current?.reset();
};
return (
{/* Form fields */}
);
}`
},
exports: ['Former', 'FormerDialog', 'FormerModel', 'FormerPopover', 'FormerRestHeadSpecAPI'],
name: 'Former',
wrappers: ['FormerDialog', 'FormerModel', 'FormerPopover']
},
FormerControllers: {
controls: ['TextInputCtrl', 'PasswordInputCtrl', 'NativeSelectCtrl', 'TextAreaCtrl', 'SwitchCtrl', 'ButtonCtrl', 'IconButtonCtrl'],
description: 'Pre-built form input controls for use with Former',
examples: {
basic: `import { TextInputCtrl, PasswordInputCtrl, NativeSelectCtrl, ButtonCtrl } from '@warkypublic/oranguru';
Save
`
},
exports: ['TextInputCtrl', 'PasswordInputCtrl', 'NativeSelectCtrl', 'TextAreaCtrl', 'SwitchCtrl', 'ButtonCtrl', 'IconButtonCtrl'],
name: 'FormerControllers'
},
GlobalStateStore: {
description: 'Zustand-based global state management with automatic persistence',
examples: {
basic: `import { useGlobalStateStore } from '@warkypublic/oranguru';
function MyComponent() {
const state = useGlobalStateStore();
return (
{state.program.name}
User: {state.user.username}
Email: {state.user.email}
Connected: {state.session.connected ? 'Yes' : 'No'}
);
}`,
provider: `import { GlobalStateStoreProvider } from '@warkypublic/oranguru';
function App() {
return (
);
}`,
stateUpdates: `import { useGlobalStateStore } from '@warkypublic/oranguru';
function StateControls() {
const state = useGlobalStateStore();
const handleUpdateProgram = () => {
state.setProgram({
name: 'My App',
slug: 'my-app',
description: 'A great application'
});
};
const handleUpdateUser = () => {
state.setUser({
username: 'john_doe',
email: 'john@example.com',
fullNames: 'John Doe'
});
};
const handleToggleTheme = () => {
state.setUser({
theme: {
...state.user.theme,
darkMode: !state.user.theme?.darkMode
}
});
};
return (
);
}`,
layout: `import { useGlobalStateStore } from '@warkypublic/oranguru';
function LayoutControls() {
const state = useGlobalStateStore();
return (
);
}`,
outsideReact: `import { GlobalStateStore } from '@warkypublic/oranguru';
// Access state outside React components
const currentState = GlobalStateStore.getState();
console.log('API URL:', currentState.session.apiURL);
// Update state outside React
GlobalStateStore.getState().setAuthToken('new-token');
GlobalStateStore.getState().setApiURL('https://new-api.com');
// Subscribe to changes
const unsubscribe = GlobalStateStore.subscribe(
(state) => state.session.connected,
(connected) => console.log('Connected:', connected)
);`
},
exports: ['GlobalStateStore', 'GlobalStateStoreProvider', 'useGlobalStateStore', 'useGlobalStateStoreContext'],
hook: 'useGlobalStateStore()',
name: 'GlobalStateStore',
provider: 'GlobalStateStoreProvider',
store: 'GlobalStateStore'
},
Gridler: {
adaptors: ['LocalDataAdaptor', 'APIAdaptorForGoLangv2', 'FormAdaptor'],
component: 'Gridler',
description: 'Powerful data grid component with sorting, filtering, and pagination',
examples: {
basic: `import { Gridler } from '@warkypublic/oranguru';
const columns = [
{ id: 'name', title: 'Name', width: 200 },
{ id: 'email', title: 'Email', width: 250 },
{ id: 'role', title: 'Role', width: 150 }
];
const data = [
{ name: 'John Doe', email: 'john@example.com', role: 'Admin' },
{ name: 'Jane Smith', email: 'jane@example.com', role: 'User' }
];
function GridExample() {
return (
);
}`,
customCell: `// Custom cell rendering with icons
const columns = [
{
id: 'status',
title: 'Status',
width: 100,
Cell: (row) => {
const icon = row?.active ? '✅' : '❌';
return {
data: \`\${icon} \${row?.status}\`,
displayData: \`\${icon} \${row?.status}\`
};
}
},
{ id: 'name', title: 'Name', width: 200 }
];`,
api: `import { Gridler, GlidlerAPIAdaptorForGoLangv2 } from '@warkypublic/oranguru';
import { useRef } from 'react';
function APIGridExample() {
const gridRef = useRef(null);
const columns = [
{ id: 'id', title: 'ID', width: 100 },
{ id: 'name', title: 'Name', width: 200 },
{ id: 'status', title: 'Status', width: 150 }
];
return (
console.log('Selected:', values)}
>
);
}`,
withForm: `// Gridler with Former integration for inline editing
import { Gridler, GlidlerAPIAdaptorForGoLangv2 } from '@warkypublic/oranguru';
import { FormerDialog } from '@warkypublic/oranguru';
import { TextInputCtrl, NativeSelectCtrl } from '@warkypublic/oranguru';
import { useState, useRef } from 'react';
function EditableGrid() {
const gridRef = useRef(null);
const [formProps, setFormProps] = useState({
opened: false,
request: null,
values: null,
onClose: () => setFormProps(prev => ({
...prev,
opened: false,
request: null,
values: null
})),
onChange: (request, data) => {
gridRef.current?.refresh({ value: data });
}
});
const columns = [
{ id: 'id', title: 'ID', width: 100 },
{ id: 'name', title: 'Name', width: 200 },
{ id: 'type', title: 'Type', width: 150 }
];
return (
<>
{
setFormProps(prev => ({
...prev,
opened: true,
request: request,
values: data
}));
}}
/>
>
);
}`,
refMethods: `// Using Gridler ref methods for programmatic control
import { Gridler } from '@warkypublic/oranguru';
import { useRef } from 'react';
function GridWithControls() {
const gridRef = useRef(null);
return (
<>
>
);
}`,
sections: `// Gridler with custom side sections
import { Gridler } from '@warkypublic/oranguru';
import { useState } from 'react';
function GridWithSections() {
const [sections, setSections] = useState({
top: Top Bar
,
bottom: Bottom Bar
,
left: L
,
right: R
});
return (
);
}`
},
exports: ['Gridler', 'GlidlerLocalDataAdaptor', 'GlidlerAPIAdaptorForGoLangv2', 'GlidlerFormAdaptor'],
hook: 'useGridlerStore()',
name: 'Gridler'
},
MantineBetterMenu: {
description: 'Enhanced context menus with better positioning and visibility control',
examples: {
provider: `import { MantineBetterMenusProvider } from '@warkypublic/oranguru';
import { MantineProvider } from '@mantine/core';
function App() {
return (
);
}`,
contextMenu: `import { useMantineBetterMenus } from '@warkypublic/oranguru';
function MyComponent() {
const { show, hide } = useMantineBetterMenus();
const handleContextMenu = (e) => {
e.preventDefault();
show('context-menu', {
x: e.clientX,
y: e.clientY,
items: [
{
label: 'Edit',
onClick: () => console.log('Edit clicked')
},
{
label: 'Copy',
onClick: () => console.log('Copy clicked')
},
{
isDivider: true
},
{
label: 'Delete',
onClick: () => console.log('Delete clicked'),
color: 'red'
}
]
});
};
return (
Right-click me for a context menu
);
}`,
asyncActions: `import { useMantineBetterMenus } from '@warkypublic/oranguru';
function AsyncMenuExample() {
const { show } = useMantineBetterMenus();
const handleClick = (e) => {
show('async-menu', {
x: e.clientX,
y: e.clientY,
items: [
{
label: 'Save',
onClickAsync: async () => {
await fetch('/api/save', { method: 'POST' });
console.log('Saved successfully');
}
},
{
label: 'Load Data',
onClickAsync: async () => {
const data = await fetch('/api/data').then(r => r.json());
console.log('Data loaded:', data);
}
}
]
});
};
return ;
}`,
customRenderer: `import { useMantineBetterMenus } from '@warkypublic/oranguru';
function CustomMenuExample() {
const { show } = useMantineBetterMenus();
const handleClick = (e) => {
show('custom-menu', {
x: e.clientX,
y: e.clientY,
items: [
{
renderer: ({ loading }) => (
{loading ? 'Processing...' : 'Custom Item'}
)
}
]
});
};
return ;
}`
},
exports: ['MantineBetterMenusProvider', 'useMantineBetterMenus'],
hook: 'useMantineBetterMenus()',
name: 'MantineBetterMenu',
provider: 'MantineBetterMenusProvider'
}
};
class OranguruMCPServer {
constructor() {
this.server = new Server(
{
name: 'oranguru-docs',
version: '0.0.31',
},
{
capabilities: {
resources: {},
tools: {},
},
}
);
this.setupHandlers();
this.server.onerror = (error) => console.error('[MCP Error]', error);
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Oranguru MCP server running on stdio');
}
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
description: 'Get documentation for a specific Oranguru component',
inputSchema: {
properties: {
component: {
description: 'The component name',
enum: Object.keys(COMPONENTS),
type: 'string',
},
},
required: ['component'],
type: 'object',
},
name: 'get_component_docs',
},
{
description: 'Generate code example for a specific Oranguru component',
inputSchema: {
properties: {
component: {
description: 'The component name',
enum: Object.keys(COMPONENTS),
type: 'string',
},
variant: {
description: "Example variant (e.g., 'basic', 'local', 'server')",
type: 'string',
},
},
required: ['component'],
type: 'object',
},
name: 'get_component_example',
},
{
description: 'List all available Oranguru components',
inputSchema: {
properties: {},
type: 'object',
},
name: 'list_components',
},
],
}));
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { arguments: args, name } = request.params;
switch (name) {
case 'get_component_docs':
if (!args.component || !COMPONENTS[args.component]) {
throw new Error(`Component ${args.component} not found`);
}
return {
content: [
{
text: JSON.stringify(COMPONENTS[args.component], null, 2),
type: 'text',
},
],
};
case 'get_component_example':
if (!args.component || !COMPONENTS[args.component]) {
throw new Error(`Component ${args.component} not found`);
}
const component = COMPONENTS[args.component];
const variant = args.variant || Object.keys(component.examples)[0];
const example = component.examples[variant];
if (!example) {
throw new Error(`Variant ${variant} not found for ${args.component}`);
}
return {
content: [
{
text: example,
type: 'text',
},
],
};
case 'list_components':
return {
content: [
{
text: JSON.stringify(
Object.entries(COMPONENTS).map(([key, comp]) => ({
description: comp.description,
exports: comp.exports,
name: key,
})),
null,
2
),
type: 'text',
},
],
};
default:
throw new Error(`Unknown tool: ${name}`);
}
});
// List resources
this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
description: 'Main documentation for the Oranguru library',
mimeType: 'text/markdown',
name: 'Oranguru Documentation',
uri: 'oranguru://docs/readme',
},
{
description: 'List of all available components',
mimeType: 'application/json',
name: 'Component List',
uri: 'oranguru://docs/components',
},
],
}));
// Read resources
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
if (uri === 'oranguru://docs/readme') {
const readmePath = join(__dirname, '..', 'README.md');
const readme = readFileSync(readmePath, 'utf-8');
return {
contents: [
{
mimeType: 'text/markdown',
text: readme,
uri,
},
],
};
}
if (uri === 'oranguru://docs/components') {
return {
contents: [
{
mimeType: 'application/json',
text: JSON.stringify(
Object.entries(COMPONENTS).map(([key, comp]) => ({
description: comp.description,
exports: comp.exports,
name: key,
})),
null,
2
),
uri,
},
],
};
}
throw new Error(`Resource not found: ${uri}`);
});
}
}
const server = new OranguruMCPServer();
server.run().catch(console.error);