{"id":51235583,"url":"https://github.com/rupertgermann/text-to-typo3","last_synced_at":"2026-06-28T20:01:36.946Z","repository":{"id":364129153,"uuid":"1201930818","full_name":"rupertgermann/text-to-typo3","owner":"rupertgermann","description":"AI chat interface for TYPO3 via MCP, with OAuth or token-based auth, streaming conversations, inline tool calls, and OpenAI or LM Studio model support.","archived":false,"fork":false,"pushed_at":"2026-06-11T18:37:11.000Z","size":1065,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-11T20:05:48.461Z","etag":null,"topics":["lm-studio","mcp","nextjs","openai","react","typo3"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rupertgermann.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-05T11:07:40.000Z","updated_at":"2026-06-11T18:35:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rupertgermann/text-to-typo3","commit_stats":null,"previous_names":["rupertgermann/text-to-typo3"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/rupertgermann/text-to-typo3","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rupertgermann%2Ftext-to-typo3","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rupertgermann%2Ftext-to-typo3/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rupertgermann%2Ftext-to-typo3/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rupertgermann%2Ftext-to-typo3/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rupertgermann","download_url":"https://codeload.github.com/rupertgermann/text-to-typo3/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rupertgermann%2Ftext-to-typo3/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34901959,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lm-studio","mcp","nextjs","openai","react","typo3"],"created_at":"2026-06-28T20:01:36.013Z","updated_at":"2026-06-28T20:01:36.939Z","avatar_url":"https://github.com/rupertgermann.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# text-to-typo3\n\n### Prompt your TYPO3 Website's content into existence with AI\n\n`text-to-typo3` is a Next.js App Router application for chatting with a TYPO3 instance through its MCP server (https://github.com/hauptsacheNet/typo3-mcp-server). Editors authenticate with TYPO3 OAuth or local MCP token mode, work inside conversation threads, inspect tool calls inline, approve TYPO3 writes when needed, and use OpenAI, LM Studio, or custom OpenAI-compatible model providers from the same interface.\n\nThe project is released under the MIT license.\n\n## What The App Does\n\n- Authenticates against TYPO3 with OAuth 2.0 Authorization Code + PKCE.\n- Stores encrypted TYPO3 session tokens in SQLite and restores sessions across refreshes.\n- Streams AI responses token-by-token with the Vercel AI SDK.\n- Persists conversations, messages, tool calls, and per-user model settings in SQLite.\n- Connects server-side to the TYPO3 MCP endpoint and forwards the authenticated TYPO3 bearer token on every MCP request.\n- Applies a consistent API auth wrapper and JSON error shape across app API routes.\n- Supports multi-step MCP tool execution so the assistant can inspect TYPO3 state, fetch schema details, and continue to follow-up tool calls inside the same response.\n- Protects MCP requests with request timeouts, expiring session cache entries, and tool-cache invalidation when Write Approval mode changes.\n- Guides TYPO3 write operations toward schema-aware retries when a `WriteTable` call returns validation or missing-input feedback.\n- Supports TYPO3 tool calling for OpenAI, LM Studio, and custom OpenAI-compatible providers through the same server-side MCP bridge, with provider-specific model routing where needed.\n- Surfaces pending Write Approval through a persistent banner above the composer and a highlighted tool card in the transcript.\n- Renders MCP tool calls inline in the chat and in a filterable Activity sidebar.\n- Supports message editing and rerunning from an earlier user prompt.\n- Supports image attachments through drag-and-drop or the file picker.\n- Supports cached, debounced conversation search, inline rename, delete, and Markdown export.\n- Supports provider-aware model selection from OpenAI, LM Studio, and custom endpoints, including context-window hints in the UI.\n- Queries model providers in parallel with per-provider timeouts, provider status, and persisted context-window hints for chat budgeting.\n- Includes a scaffold CLI for provisioning a local TYPO3 + DDEV environment and writing matching app configuration.\n\n## Screenshots\n\n| Chat Interface | Settings Modal |\n|:--:|:--:|\n| ![Chat Interface](./docs/screens/chat.png) | ![Settings Modal](./docs/screens/settings.png) |\n\n## Tech Stack\n\n- Next.js 16 App Router\n- React 19\n- Vercel AI SDK\n- `@ai-sdk/openai`\n- SQLite via `better-sqlite3`\n- Drizzle ORM\n- Tailwind CSS\n- shadcn/ui and Base UI primitives\n- Iron Session\n\n## Requirements\n\n### App runtime\n\n- Node.js 20+\n- pnpm\n\n### TYPO3 scaffold workflow\n\n- `ddev`\n- `composer`\n- `php`\n\n## Environment Variables\n\nCopy `.env.example` to `.env.local` in the project root and fill in your own values.\n\n```bash\nTYPO3_BASE_URL=https://your-typo3.example\nTYPO3_MCP_URL=\nTYPO3_MCP_ACCESS_TOKEN=\nTYPO3_LOCAL_USER_NAME=Local TYPO3 Token\nTYPO3_OAUTH_CLIENT_ID=your-client-id\nTYPO3_OAUTH_CLIENT_SECRET=your-client-secret\nOPENAI_API_KEY=your-openai-api-key\nENCRYPTION_KEY=generate-a-64-char-hex-key\nSESSION_SECRET=generate-a-long-random-secret\nNEXT_PUBLIC_APP_URL=http://localhost:3000\nTYPO3_MCP_SYSTEM_PROMPT=Optional TYPO3-specific system prompt text\nTYPO3_AGENT_MAX_STEPS=12\nMODEL_CATALOG_TIMEOUT_MS=4000\nDATABASE_PATH=data/app.db\n```\n\n### Notes\n\n- `TYPO3_BASE_URL` is always required.\n- `TYPO3_OAUTH_CLIENT_ID` and `TYPO3_OAUTH_CLIENT_SECRET` are required in OAuth mode.\n- `TYPO3_MCP_URL` can point directly at the MCP endpoint, including the tokenized URL from the TYPO3 MCP Server backend screen.\n- `TYPO3_MCP_ACCESS_TOKEN` enables token-based local mode when the TYPO3 instance expects a bearer token instead of browser OAuth.\n- `TYPO3_LOCAL_USER_NAME` controls the synthetic local display name used in token-based mode.\n- `OPENAI_API_KEY` enables the default OpenAI model catalog and acts as the fallback server-side key when a user has not stored a personal OpenAI key in Settings.\n- `ENCRYPTION_KEY` is used for secrets stored in SQLite.\n- `SESSION_SECRET` secures the Iron Session cookie.\n- `NEXT_PUBLIC_APP_URL` should match the externally reachable app URL used in the TYPO3 OAuth callback.\n- `TYPO3_MCP_SYSTEM_PROMPT` is appended to the chat system prompt for instance-specific guidance.\n- `TYPO3_AGENT_MAX_STEPS` controls the maximum model/tool round-trips in one chat request. The default is `12`.\n- `MODEL_CATALOG_TIMEOUT_MS` controls the per-provider model catalog timeout. The default is `4000`.\n- `DATABASE_PATH` points at the SQLite database file. The default is `data/app.db`.\n- Never commit `.env.local`, scaffold output, or generated TYPO3 credentials.\n\nDetailed TYPO3 setup, Composer packages, and OAuth value mapping are documented in [docs/typo3-setup.md](./docs/typo3-setup.md).\n\n## Installation\n\n```bash\npnpm install\n```\n\nCreate your local environment file:\n\n```bash\ncp .env.example .env.local\n```\n\n## TYPO3 Instance Setup\n\nThe TYPO3 instance needs the MCP server extension and TYPO3 OAuth endpoints that match this app's auth flow.\n\nTwo TYPO3 connection modes are supported:\n\n- OAuth mode for full TYPO3 browser login\n- token-based local mode using the MCP token URL shown in the TYPO3 backend MCP Server screen\n\n### Required Composer packages in TYPO3\n\n```bash\ncomposer require hn/typo3-mcp-server\n```\n\n`hn/typo3-mcp-server` requires TYPO3 13.4+ and pulls in `typo3/cms-workspaces` as a dependency.\n\n### Optional TYPO3 packages\n\n```bash\ncomposer require georgringer/news\n```\n\n`georgringer/news` is only needed if the TYPO3 instance should expose news records for MCP workflows or scaffolded demo content.\n\n### Exact `.env.local` value mapping\n\n- `TYPO3_BASE_URL`: the TYPO3 site origin, for example `https://my-project.ddev.site`\n- `TYPO3_MCP_URL`: optional full MCP endpoint URL, including `?token=...` when using token mode\n- `TYPO3_MCP_ACCESS_TOKEN`: optional raw MCP token when the TYPO3 instance accepts bearer-token MCP requests\n- `TYPO3_OAUTH_CLIENT_ID`: the OAuth client ID registered in TYPO3 for this app\n- `TYPO3_OAUTH_CLIENT_SECRET`: the matching OAuth client secret from TYPO3\n- `NEXT_PUBLIC_APP_URL`: the externally reachable URL of this Next.js app, for example `http://localhost:3000`\n\nThe app uses these TYPO3 endpoints:\n\n- `${TYPO3_BASE_URL}/oauth/authorize`\n- `${TYPO3_BASE_URL}/oauth/token`\n- `${TYPO3_BASE_URL}/oauth/userinfo`\n- `${TYPO3_BASE_URL}/oauth/revoke`\n- `${TYPO3_MCP_URL}` or `${TYPO3_BASE_URL}/mcp`\n\nThe step-by-step process for getting those values is documented in [docs/typo3-setup.md](./docs/typo3-setup.md).\n\n## Running The App\n\n### Development\n\n```bash\npnpm dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000).\n\nIn OAuth mode, unauthenticated requests redirect to `/api/auth/login`, which starts the TYPO3 OAuth flow. In token-based MCP mode, the app redirects directly into the chat UI without the browser OAuth round-trip.\n\nNext.js development requests under `/_next/*` bypass the auth proxy so Fast Refresh and other dev-runtime internals can connect directly to the dev server.\n\n### Production build\n\n```bash\npnpm build\npnpm start\n```\n\n## Available Scripts\n\n```bash\npnpm dev\npnpm dev:turbopack\npnpm build\npnpm start\npnpm typecheck\npnpm test\npnpm lint\npnpm scaffold\npnpm db:generate\npnpm db:migrate\npnpm db:studio\n```\n\n### Script reference\n\n- `pnpm dev`: starts the Next.js development server.\n- `pnpm dev:turbopack`: starts the Next.js development server with Turbopack.\n- `pnpm build`: creates the production build.\n- `pnpm start`: serves the production build.\n- `pnpm typecheck`: runs TypeScript without emitting build artifacts.\n- `pnpm test`: runs the Vitest suite.\n- `pnpm lint`: runs ESLint.\n- `pnpm scaffold`: provisions or refreshes a local TYPO3 scaffold plan.\n- `pnpm db:generate`: generates Drizzle SQL from schema changes.\n- `pnpm db:migrate`: runs Drizzle migrations.\n- `pnpm db:studio`: opens Drizzle Studio for local database inspection.\n\n## Core User Flows\n\n### Authentication\n\n- Visiting the app without a valid session starts TYPO3 OAuth login in OAuth mode and opens the chat directly in token-based MCP mode.\n- The callback exchanges the authorization code, stores encrypted tokens in SQLite, and writes the Iron Session cookie.\n- Expired access tokens are refreshed transparently.\n- Logout revokes TYPO3 tokens when possible and clears the local session.\n\n### Conversations\n\n- The home route redirects to the latest conversation or creates a default one for first-time users.\n- Conversations are listed in a left sidebar, ordered by last activity.\n- Conversations can be created, renamed inline, deleted, searched with a debounced cached query, and exported as Markdown.\n- Sidebar results stay visible while background refreshes run, and same-key requests share in-flight fetches.\n- The first user prompt in a new conversation becomes the basis of the auto-generated title.\n\n### Chat\n\n- Messages stream in real time.\n- Assistant responses render Markdown with GFM tables and code blocks.\n- User messages support copy, timestamp hover state, edit-and-rerun, and image attachments.\n- Stopping generation preserves the partial response.\n- Conversation history restores after reload.\n- TYPO3 MCP sessions can span several tool steps inside one response, up to `TYPO3_AGENT_MAX_STEPS` model/tool round-trips per request.\n- Chat requests resolve the turn, provider, and persistence plan through dedicated modules before streaming.\n- Long tool outputs are condensed or older turns are dropped for model input when the active context window requires budgeting; persisted messages stay unchanged.\n- When TYPO3 write validation fails, the assistant is instructed to inspect schema details and retry with corrected `WriteTable` input before treating the task as blocked.\n\n### Tool calls\n\n- MCP tools are fetched server-side and cached per session.\n- MCP calls use request-level timeouts and categorized errors for hung or unreachable TYPO3 MCP servers.\n- The app initializes and reuses TYPO3 MCP session IDs when the TYPO3 server supports MCP session headers, and session cache entries expire automatically.\n- Tool caches are keyed by Conversation Write Approval mode so auto-approve toggles use the correct tool definitions.\n- Read and write tool calls are rendered as collapsible cards in the chat thread.\n- The Activity sidebar shows the same tool traffic in chronological order with read/write filters.\n- Write results can expose a direct TYPO3 backend record link when the MCP response includes record metadata.\n- Write operations pause for approval unless the Conversation has auto-approve writes enabled. Pending approvals show Approve/Deny controls in the banner and in the relevant tool card.\n- The upstream TYPO3 MCP server toolset used by the app includes `GetPageTree`, `GetPage`, `ListTables`, `ReadTable`, `Search`, `GetTableSchema`, `GetFlexFormSchema`, and `WriteTable`.\n\n### Model selection\n\n- The header shows the selected model for the active conversation.\n- The settings modal includes OpenAI, LM Studio, and custom OpenAI-compatible provider configuration.\n- Per-user settings, configured providers, selected model IDs, and context-window hints are persisted in SQLite.\n- Model providers are queried in parallel with per-provider status. Slow or unreachable providers appear as unavailable while other provider results stay usable.\n- Settings render saved values immediately while provider catalogs load in the background.\n- Context-window information is shown in model cards and persisted for chat budgeting.\n- The default selected model falls back to `gpt-5.4-mini` when no user preference is stored.\n- `gpt-5.4-nano` uses the provider's built-in MCP server tool integration; other OpenAI-compatible models use the app's TYPO3 MCP bridge.\n- LM Studio and custom OpenAI-compatible models use the chat-completions path and the same server-side TYPO3 MCP bridge as the app-managed OpenAI path.\n- For TYPO3 mutation requests on OpenAI-compatible chat-completions models, the chat loop keeps tool calling active until a write succeeds or the configured step cap is reached.\n\n## UI Overview\n\n### Header\n\n- Active conversation title\n- Current TYPO3 user identity\n- Selected model indicator\n- Theme toggle\n- Settings modal\n- Markdown export action\n- Logout action\n\n### Left sidebar\n\n- Conversation list\n- Search field\n- New conversation button\n- Inline rename and delete controls\n- Mobile sheet presentation on narrow screens\n\n### Main chat area\n\n- Streaming message list\n- Inline MCP tool cards\n- Pending Write Approval banner\n- Composer with message editing state\n- Drag-and-drop image attachments\n- Stop button during generation\n\n### Right sidebar\n\n- Activity timeline for MCP tool calls\n- Read/write filters\n\n## Data Storage\n\nThe app stores its local database in `data/app.db`.\n\nThe current schema includes:\n\n- `users`\n- `sessions`\n- `conversations`\n- `messages`\n- `user_settings`\n\nThe schema includes indexes for conversation/message/session lookup paths and SQL aggregates for assistant token totals. Existing development databases are repaired on app startup when an expected non-production column is missing.\n\n## TYPO3 Scaffold CLI\n\nThe scaffold command prepares a TYPO3-oriented local environment and matching app configuration.\n\n### Basic usage\n\n```bash\npnpm scaffold\n```\n\n### Options\n\n```bash\npnpm scaffold --dry-run\npnpm scaffold --force\npnpm scaffold --instance-dir typo3-instance\npnpm scaffold -i typo3-instance\npnpm scaffold --php-version 8.3\npnpm scaffold --project-name my-typo3-demo\npnpm scaffold --help\n```\n\n### Behavior\n\n- Checks that `ddev`, `composer`, and `php` are available.\n- Configures a TYPO3 DDEV project.\n- Installs TYPO3 base distribution and `hn/typo3-mcp-server`.\n- Creates generated credentials and writes `.env.local`.\n- Persists scaffold state under `typo3-instance/.codex-scaffold/`.\n- Writes a human-readable scaffold summary with follow-up guidance.\n- Re-running the command on an already scaffolded project exits cleanly.\n- `--force` refreshes generated artifacts and rewrites scaffold-managed files.\n\n### Help output\n\n```bash\npnpm scaffold --help\n```\n\nThe CLI supports these automation hooks:\n\n- `TYPO3_SCAFFOLD_WORKSPACE_COMMAND`\n- `TYPO3_SCAFFOLD_DEMO_CONTENT_COMMAND`\n- `TYPO3_SCAFFOLD_NEWS_COMMAND`\n- `TYPO3_SCAFFOLD_OAUTH_CLIENT_COMMAND`\n\nThe scaffold flow also exports these hook context variables while those commands run:\n\n- `TYPO3_SCAFFOLD_PROJECT_NAME`\n- `TYPO3_SCAFFOLD_INSTANCE_DIR`\n- `TYPO3_SCAFFOLD_BACKEND_URL`\n- `TYPO3_SCAFFOLD_SITE_NAME`\n- `TYPO3_SCAFFOLD_WORKSPACE_NAME`\n\nEach hook is a shell command that runs inside the scaffold flow, which makes it possible to automate TYPO3-specific workspace creation, demo content seeding, news seeding, and OAuth client registration without hardcoding project-specific TYPO3 commands in the repository.\n\n## LM Studio Configuration\n\nLM Studio uses its OpenAI-compatible endpoint.\n\nTypical setup:\n\n1. Start LM Studio locally.\n2. Copy the API base URL, usually `http://localhost:1234/v1`.\n3. Open Settings in the app.\n4. Paste the base URL into the LM Studio section.\n5. Click `Fetch models`.\n6. Select a model in Settings.\n\nThe model catalog endpoint accepts an LM Studio base URL override, which is how the Settings UI fetches available local models before saving a selection.\n\n## OpenAI Configuration\n\nOpenAI models are available when either:\n\n- `OPENAI_API_KEY` is set server-side, or\n- a user stores a personal OpenAI API key in Settings.\n\nThe user-specific key takes precedence for that user.\n\n## Custom OpenAI-Compatible Providers\n\nSettings can store additional OpenAI-compatible providers. Each custom provider has:\n\n- display name\n- base URL\n- optional API key\n\nCustom provider API keys are encrypted in SQLite. Custom provider model IDs use the `custom:\u003cprovider-id\u003e:\u003cremote-model-id\u003e` format internally, while Settings shows the provider display name and remote model name.\n\n## File Attachments\n\nThe composer accepts image attachments through:\n\n- drag-and-drop onto the composer\n- the attachment button in the composer\n\nAttached images are sent as AI SDK file parts and are persisted with the message history.\n\n## Export Format\n\nConversation export is available from the conversation header. The generated Markdown file includes:\n\n- conversation metadata\n- the full ordered message transcript\n- serialized tool-call data for messages that include tool output\n- assistant messages that contain tool-only steps, even when the natural-language response is empty\n\n## Manual Test Plan\n\nA short manual test plan lives in [docs/testing.md](./docs/testing.md).\n\n## Security Notes\n\n- Secrets belong in `.env.local` or your deployment platform's secret storage, not in Git.\n- `pnpm scaffold` generates local credentials and a scaffold summary; both stay ignored by default.\n- In production, `SESSION_SECRET` must be set explicitly.\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n\n## Project Structure\n\n```text\nsrc/\n  app/\n    api/\n    conversations/\n  components/\n    chat/\n    conversations/\n    settings/\n    ui/\n  lib/\nscripts/\ndocs/\ndrizzle/\n```\n\n## Current Development Notes\n\n- The app assumes one TYPO3 instance per deployment, configured by environment variables.\n- LM Studio and custom provider support are wired through the same settings and chat flow as OpenAI-compatible providers.\n- The scaffold command supports hook-based TYPO3 automation for workspace, demo content, news, and OAuth registration tasks.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frupertgermann%2Ftext-to-typo3","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frupertgermann%2Ftext-to-typo3","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frupertgermann%2Ftext-to-typo3/lists"}