# Inspector V2 This is an application for inspecting MCP servers. Has three incarnations, Web, TUI, and CLI. ## Project Structure ``` inspector/ ├── clients/ │ ├── web/ # Web client code │ ├── cli/ # CLI client code │ ├── tui/ # TUI client code │ ├── launcher/ # Shared launcher ├── core/ # Shared core code ├── soecification/ # Build specification ... ``` ## Maintenance Rules ### Keep documentation files up to date - When adding, removing, renaming, or changing the purpose of any file or folder, update the corresponding entry in the main README.md and/or the related clients/*/README.md - When the structure of the project, the tech stack, or the developer setup changes, update appropriate README.md files with the details. - When adding new commands, dependencies, or architectural patterns, update the relevant sections of appropriate README.md files as well. - When rules for implementation and testing change, update this file AGENTS.md ### Always test new or modified coderea - Ensure all code has corresponding tests - Ensure test coverage for each file is at least 90% - In unit tests that expect error output, suppress it from the console ### Responding to Code Reviews - When asked to respond to a code review of a PR, - it is not necessary to implement all suggestions - you are free to implement suggestions in a different way or to ignore if there is a good reason - after making the changes, respond to each review comment with what was done (or why it was ignored) ### Lint-fixed, Formatted code - Ensure linting and formatting are applied after every change - ALWAYS do `npm run format`, `npm run lint`, `npm run typecheck`, `npm run test` and `npm run build` before pushing any changes ### Typescript instructions - Use TypeScript for all new code - Follow TypeScript best practices and coding standards - NEVER use 'any' as a type - NEVER suppress error types (e.g., no-unused-vars, no-explicit-any) in the typescript or eslint configuration as a way of satisfying the linter or compiler. - Utilize type annotations and interfaces to improve code clarity and maintainability - Leverage TypeScript's type inference and static analysis features for better code quality and refactoring - Use type guards and type assertions to handle potential type mismatches and ensure type safety - Take advantage of TypeScript's advanced features like generics, type aliases, and conditional types to write more expressive and reusable code - Regularly review and refactor TypeScript code to ensure it remains well-structured and adheres to evolving best practices ## React instructions - UI Components - We are using the Mantine component library for UI. - Instructions are at https://mantine.dev/llms.txt - Avoid using div and other basic HTML elements for layout purposes. - Prefer Mantine's Box, Group, and Stack components for layout. - Use Mantine's theme and styling utilities to ensure a consistent and responsive design. - NEVER use inline styles on a component. - NEVER use raw hex values (`#ddd`, `#94a3b8`, etc.) or `rgba()` literals for colors in component props or theme files. Use `--inspector-*` CSS custom properties defined in `App.css :root` (e.g., `c: 'var(--inspector-text-primary)'`). If no existing token fits, add one to `:root` first. - NEVER add a CSS class to a Mantine component when the styles can instead be expressed as component props or a theme variant. CSS classes are a last resort. - PREFER component props (via `.withProps()`) to CSS for behavioral and visual styles. - PREFER defining styles as theme variants (via `Component.extend()` in `src/theme/.ts`) over CSS classes. Each Mantine component with custom variants has its own file in `src/theme/`, exporting a `Theme` constant. The barrel `src/theme/index.ts` re-exports them all and `theme.ts` imports from the barrel. Flat CSS properties (margin, padding, background, border, color, font-size, etc.) belong in the theme. Only pseudo-selectors, nested child selectors, keyframes, and native HTML element styles belong in App.css. - App.css must contain ONLY styles that cannot be expressed in the Mantine theme: `@keyframes`, pseudo-selectors (`:hover`, `:focus`), cross-component hover relationships, nested child-element selectors for third-party HTML output (e.g. ReactMarkdown), and styles for native HTML elements (`img`, `iframe`). When refactoring a component, actively move any flat CSS properties out of App.css and into theme variants or `.withProps()` constants. - NEVER use inline code; instead extract to functions in the same file, exported or located in a shared location if immediately reusable. - In a component's file, for sub-components: - ALWAYS use Mantine components for layout and content, configured with props for styling and behavior. - ALWAYS declare a subcomponent as a named constant using `.withProps()` if it has two or more props. - NEVER use `Box` for subcomponent constants — `Box` does not support `.withProps()`. Use `Group`, `Stack`, `Flex`, `Text`, `Paper`, `UnstyledButton`, or `Image` instead. Pick the component that best matches the purpose: `Paper` for bordered/surfaced containers, `Text` for any text or content wrapper, `Stack`/`Group`/`Flex` for layout. - NEVER use a CSS class on a subcomponent constant when the styles can be expressed as a Mantine theme variant instead. Define variants in `src/theme/.ts` using `Component.extend({ styles: (_theme, props) => { ... } })` and reference them with `variant="variantName"` on the component or in `.withProps()`. - CSS classes are ONLY acceptable on subcomponents for styles that cannot be expressed as flat CSS-in-JS properties in the theme — specifically: pseudo-selectors (`:hover`, `:focus`), cross-component hover relationships (`.parent:hover .child`), nested child-element selectors (`.wrapper p`, `.wrapper code`), `@keyframes` definitions, and native HTML elements (`img`, `iframe`) that are not Mantine components. - When a theme variant needs a CSS class for nested/pseudo selectors, use `classNames` in the theme extension to auto-assign it — never add `className` manually in JSX for theme-styled components. - Example — subcomponent constant with `withProps`: ```tsx const CardContent = Group.withProps({ flex: 1, align: 'flex-start', justify: 'space-between', wrap: 'nowrap', }); return ... ``` - Example — theme variant with auto-assigned className for nested selectors: ```tsx // src/theme/Paper.ts export const ThemePaper = Paper.extend({ classNames: (_theme, props) => { if (props.variant === 'message') return { root: 'message' }; return {}; }, styles: (_theme, props) => { if (props.variant === 'message') { return { root: { padding: '1.5rem', borderRadius: 12 } }; } return { root: {} }; }, }), // Component.tsx const MessageContainer = Paper.withProps({ variant: 'message' }); ```