-
-
Notifications
You must be signed in to change notification settings - Fork 1
refactor: Rewrite CLAUDE.md as concise notes instead of documentation #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
9967d87
refactor: Rewrite CLAUDE.md as concise notes instead of documentation
claude 204ce92
docs: Add testing package to project map
claude 216261a
fix: Address PR review feedback on CLAUDE.md
claude c364f53
fix: Address additional PR feedback
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,197 +1,70 @@ | ||
| # MCP AppsKit Development Guidelines | ||
| # MCP AppsKit | ||
|
|
||
| A TypeScript framework for building interactive MCP applications that work with both **MCP Apps** and **ChatGPT (OpenAI Apps SDK)** from a single codebase. | ||
| pnpm monorepo + Nx. Dual-protocol framework: MCP Apps + ChatGPT from single codebase. | ||
|
|
||
| ## Project Structure | ||
|
|
||
| This is a **pnpm monorepo** with **Nx** for orchestration: | ||
|
|
||
| ```text | ||
| packages/ | ||
| ├── core/ # @mcp-apps-kit/core - Server framework (createApp, adapters, middleware, plugins, events) | ||
| ├── ui/ # @mcp-apps-kit/ui - Client SDK (vanilla JS, protocol detection, adapters) | ||
| ├── ui-react/ # @mcp-apps-kit/ui-react - React bindings (context, hooks) | ||
| └── create-app/ # @mcp-apps-kit/create-app - CLI scaffolder | ||
|
|
||
| examples/ | ||
| ├── minimal/ # Simple hello-world example | ||
| └── restaurant-finder/ | ||
|
|
||
| # Full-featured kanban example: https://github.com/AndurilCode/kanban-mcp-example | ||
| ``` | ||
|
|
||
| Each package has its own README with detailed API documentation. | ||
|
|
||
| ## Commands | ||
| ## Before Finishing Any Task | ||
|
|
||
| ```bash | ||
| # Root commands | ||
| pnpm install && pnpm build && pnpm test && pnpm lint && pnpm typecheck | ||
|
|
||
| # Package-specific | ||
| pnpm -C packages/core test # Test single package | ||
| pnpm -C examples/minimal dev # Run minimal example with hot reload | ||
|
|
||
| # Release | ||
| pnpm release:version:patch|minor|major | ||
| ``` | ||
|
|
||
| ## Key Dependencies | ||
|
|
||
| | Package | Purpose | | ||
| | ----------------------------------- | ----------------------------- | | ||
| | `@modelcontextprotocol/sdk` ^1.25.1 | MCP protocol | | ||
| | `express` ^5.1.0 | HTTP server | | ||
| | `zod` ^4.0.0 | Schema validation | | ||
| | `typescript` ^5.9.3 | Strict mode enabled | | ||
| | `vitest` ^4.0.16 | Testing (80% coverage target) | | ||
|
|
||
| ## Code Conventions | ||
|
|
||
| - **Strict TypeScript**: No `any` types, use `unknown` and narrow | ||
| - **No unused variables**: Remove or prefix with `_` | ||
| - **Public API**: Exports only in `index.ts` | ||
| - **Tests**: Mirror source in `tests/` (unit/, integration/, contract/) | ||
|
|
||
| ## Tool Definition Pattern | ||
|
|
||
| Always use `defineTool` and `defineUI` for type inference: | ||
|
|
||
| ```typescript | ||
| import { defineTool, defineUI } from "@mcp-apps-kit/core"; | ||
| import { z } from "zod"; | ||
|
|
||
| // Define UI for the tool (colocated pattern) | ||
| const myWidget = defineUI({ | ||
| name: "My Widget", | ||
| description: "Widget description", | ||
| html: "./ui/dist/index.html", | ||
| prefersBorder: true, | ||
| }); | ||
|
|
||
| const tool = defineTool({ | ||
| title: "My Tool", | ||
| description: "Tool description", | ||
| input: z.object({ name: z.string() }), | ||
| output: z.object({ message: z.string() }), | ||
| ui: myWidget, // Optional: links to UI resource | ||
| visibility: "both", // "model", "app", or "both" | ||
| handler: async (input) => ({ message: `Hello, ${input.name}!` }), | ||
| }); | ||
| ``` | ||
|
|
||
| ## Middleware Pattern | ||
|
|
||
| Koa-style with `async/await`: | ||
|
|
||
| ```typescript | ||
| app.use(async (context, next) => { | ||
| console.log("Before:", context.toolName); | ||
| await next(); // Must call next() | ||
| console.log("After:", context.toolName); | ||
| }); | ||
| pnpm build && pnpm test && pnpm lint && pnpm typecheck | ||
| ``` | ||
|
|
||
| ## Error Handling | ||
|
|
||
| ```typescript | ||
| import { AppError, ErrorCode } from "@mcp-apps-kit/core"; | ||
| throw new AppError({ code: ErrorCode.VALIDATION_ERROR, message: "Invalid input" }); | ||
| ``` | ||
|
|
||
| ## Plugin System | ||
|
|
||
| ```typescript | ||
| const plugin: Plugin = { | ||
| name: "my-plugin", | ||
| onInit: (app) => {}, | ||
| onStart: (app) => {}, | ||
| onShutdown: (app) => {}, | ||
| beforeToolCall: (context) => {}, | ||
| afterToolCall: (context, result) => {}, | ||
| onToolError: (context, error) => {}, | ||
| }; | ||
| ``` | ||
| All four must pass. No exceptions. Broken builds block the whole team. | ||
|
|
||
| ## Event System | ||
| ## Quick Commands | ||
|
|
||
| ```typescript | ||
| app.events.on("app:init", () => {}); | ||
| app.events.on("tool:call", ({ toolName, input }) => {}); | ||
| app.events.once("app:start", ({ port }) => {}); | ||
| ```bash | ||
| pnpm -C packages/core test # Test single package (faster iteration) | ||
| pnpm -C examples/minimal dev # Run example with hot reload | ||
| pnpm release:version:patch # Also: minor, major | ||
| ``` | ||
|
|
||
| ## UI React Hooks | ||
|
|
||
| | Hook | Purpose | | ||
| | ---------------- | ----------------------------------- | | ||
| | `useAppsClient` | Client instance for tool calls | | ||
| | `useToolResult` | Current tool result data | | ||
| | `useToolInput` | Tool input parameters | | ||
| | `useHostContext` | Host info (theme, viewport, locale) | | ||
| | `useWidgetState` | Persisted state across reloads | | ||
| | `useDisplayMode` | Fullscreen/panel mode control | | ||
| | `useFileUpload` | File upload functionality | | ||
| | `useModal` | Modal dialog management | | ||
|
|
||
| Other hooks: `useSafeAreaInsets`, `useHostStyleVariables`, `useDocumentTheme`, `useOnToolCancelled`, `useOnTeardown`, `useIntrinsicHeight`, `useView` | ||
| ## What Makes This Codebase Different | ||
|
|
||
| ## Deployment Options | ||
| - **Zod 4** (not 3) - Breaking changes from v3, check migration if something looks wrong | ||
| - **Express 5** (not 4) - Async error handling works differently | ||
| - **Strict TS** - No `any`. Use `unknown` + narrowing. We've had production bugs from implicit any | ||
| - **80% test coverage** - CI fails below this. Tests mirror source in `tests/` | ||
|
|
||
| ```typescript | ||
| // Express server (default) | ||
| await app.start({ port: 3000 }); | ||
| ## Patterns to Follow | ||
|
|
||
| // Custom Express middleware | ||
| expressApp.use("/mcp", app.handler()); | ||
| Use `defineTool` and `defineUI` (or `defineReactUI` for React components) - they provide type inference. See `examples/minimal/src/index.ts` for usage. | ||
|
|
||
| // Stdio for CLI tools | ||
| await app.getServer().connect(new StdioTransport()); | ||
| Middleware is Koa-style: always `await next()` or the chain breaks. | ||
|
|
||
| // Serverless | ||
| export default { | ||
| async fetch(request) { | ||
| return app.handleRequest(request); | ||
| }, | ||
| }; | ||
| ``` | ||
| Exports only through `index.ts` - keeps the public API clean and refactoring safe. | ||
|
|
||
| ## Protocol Abstraction | ||
| ## Common Mistakes | ||
|
|
||
| The framework auto-generates platform-specific metadata: | ||
| - Forgetting `export type` for type-only exports (causes runtime imports of types) | ||
| - Creating circular deps between packages (Nx will catch this but it's annoying) | ||
| - Committing without running the full check suite (CI will fail, wastes time) | ||
|
|
||
| ```typescript | ||
| // Your definition (using colocated UI) | ||
| const myWidget = defineUI({ name: "Widget", html: "./ui/dist/index.html" }); | ||
| tools: { my_tool: defineTool({ ui: myWidget, visibility: "both", ... }) } | ||
| ## Project Map | ||
|
|
||
| // MCP Apps: _meta.ui.resourceUri + visibility | ||
| // ChatGPT: _meta["openai/outputTemplate"] + ["openai/visibility"] | ||
| ```text | ||
| packages/core → Server framework (createApp, adapters, middleware) | ||
| packages/ui → Client SDK (vanilla JS, protocol detection) | ||
| packages/ui-react → React hooks (useAppsClient, useToolResult, useHostContext...) | ||
| packages/ui-react-builder → React UI builder (defineReactUI, vite plugin) | ||
| packages/testing → Test utilities (mocks, matchers for vitest/jest) | ||
| packages/create-app → CLI scaffolder | ||
| examples/ → Working examples to test against | ||
| ``` | ||
|
|
||
| ## HTTP Endpoints | ||
|
|
||
| | Endpoint | Purpose | | ||
| | --------- | --------------------------------------------- | | ||
| | `/health` | Health check | | ||
| | `/mcp` | MCP protocol (configurable via `serverRoute`) | | ||
| Each package README has the detailed API. Don't duplicate here. | ||
|
|
||
| ## Compatibility | ||
| ## External Docs | ||
|
|
||
| - **Node.js**: >= 20 | ||
| - **React**: 18.x or 19.x (peer dependency) | ||
| - **Zod**: ^4.0.0 required | ||
| - [MCP Spec](https://modelcontextprotocol.io/specification/2025-11-25) - Protocol details, message formats | ||
| - [OpenAI Apps SDK](https://developers.openai.com/apps-sdk) - ChatGPT integration specifics | ||
|
|
||
| ## Important Notes | ||
| --- | ||
|
|
||
| - Run full checks before PR: `pnpm build && pnpm test && pnpm lint && pnpm typecheck` | ||
| - Keep packages independent - avoid circular dependencies | ||
| - Use `export type` for type-only exports | ||
| - Maintain 80% minimum test coverage | ||
| - Never commit secrets - use environment variables | ||
| ## Learnings | ||
|
|
||
| ## External Documentation | ||
| <!-- Add specific lessons learned during development. Format: what happened → what to do instead --> | ||
|
|
||
| - [MCP Specification](https://modelcontextprotocol.io/specification/2025-11-25) | ||
| - [MCP Apps Extension](https://blog.modelcontextprotocol.io/posts/2025-11-21-mcp-apps/) | ||
| - [OpenAI Apps SDK](https://developers.openai.com/apps-sdk) | ||
| <!-- Example: | ||
| - Forgot to rebuild ui package before testing ui-react → Always `pnpm build` from root, not package | ||
| - Type error was hidden because of `any` in test mock → Use proper typed mocks from vitest | ||
| --> | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing critical error handling pattern.
The Patterns section references
defineTool,defineUI, middleware, and exports, but omits guidance on error handling. Per your established learnings, developers should useAppErrorandErrorCodefrommcp-apps-kit/corefor consistent error handling across packages. This is especially important since the codebase maintains strict patterns for reliability.Consider adding:
🤖 Prompt for AI Agents