MCP Server

Runtime Constraints

These rules apply to browser_bundler apps — the default and the only mode where Webase compiles your source. external_static apps have full freedom (any toolchain, any deps); only the Data API conventions apply there.

Every MCP session should call get_runtime_constraints first. It returns this same content as machine-readable JSON so the agent can program against it.

Entry point

The bundler picks the entry from this ordered list. Provide one.

  • src/index.tsx
  • src/index.jsx
  • src/index.ts
  • src/index.js
  • src/App.tsx
  • src/App.jsx

Import map

React 19 and react-router-dom are externalized via an import map injected into the wrapped HTML. Don't bundle them — just import bare.

{
  "react":             "https://esm.sh/react@19",
  "react/":            "https://esm.sh/react@19/",
  "react-dom":         "https://esm.sh/react-dom@19",
  "react-dom/":        "https://esm.sh/react-dom@19/",
  "react-dom/client":  "https://esm.sh/react-dom@19/client",
  "react-router-dom":  "https://esm.sh/react-router-dom?deps=react@19,react-dom@19"
}

Other npm packages

Two ways to add an external package:

  1. Direct esm.sh URL in source:
    import confetti from 'https://esm.sh/canvas-confetti'
  2. Declare in package.json and use a bare import; the bundler auto-maps each dep to https://esm.sh/<name>@<major>?deps=react@19,react-dom@19.
    { "dependencies": { "chart.js": "^4.4.0" } }

There is no npm install at runtime. Don't ship a node_modules.

Tailwind

Loaded via the CDN script tag — <script src="https://cdn.tailwindcss.com"></script> — which the bundler injects into the HTML wrapper.

  • Don't create a tailwind.config.js file — it has no effect.
  • Custom config goes inline inside public/index.html:
    <script>
      tailwind.config = {
        darkMode: 'class',
        theme: { extend: { colors: { brand: '#16a34a' } } }
      }
    </script>
  • Webase preserves the contents of <head> from public/index.html (minus charset / viewport / cdn-tailwind, which the wrapper provides).

Routing

Use HashRouter from react-router-dom. The preview iframe has no server to handle history fallbacks; HashRouter keeps routing client-side.

import { HashRouter, Routes, Route } from 'react-router-dom'

export default function App() {
  return (
    <HashRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/posts/:id" element={<Post />} />
      </Routes>
    </HashRouter>
  )
}

CSS

CSS files are converted into runtime style-injectors at bundle time, so you can import './styles.css' from any module and the styles get appended to document.head at runtime. There's no separate stylesheet output.

Application data

Define data models with create_data_model + add_data_field. Generated apps read and write records via the Data API. localStorage is for UI preferences only — never application data.

Dark mode

Use Tailwind's darkMode: 'class' strategy in your inline tailwind.config. Toggle by adding or removing the dark class on document.documentElement. Persist user choice in localStorage.