Skip to content

Commit dfa4451

Browse files
authored
docs: add AGENTS.md for AI agent contributors (#18)
Provides operational context for agents working on the core library: - commands, project structure, architecture decisions that should not be refactored, testing conventions, and boundaries.
1 parent 4819e43 commit dfa4451

1 file changed

Lines changed: 99 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# AGENTS.md
2+
3+
This file is for AI agents contributing to the webmcp-react library.
4+
For integrating webmcp-react into your app, see the [skills/](./skills) directory.
5+
6+
## Reference
7+
8+
- **WebMCP standard**: https://github.com/webmachinelearning/webmcp — the W3C spec this library implements
9+
- **API reference**: [`docs/api.md`](./docs/api.md) — this library's full API docs
10+
11+
## Commands
12+
13+
| Task | Command |
14+
|------|---------|
15+
| Install | `pnpm install` |
16+
| Build | `pnpm build` |
17+
| Test | `pnpm test` |
18+
| Test (watch) | `pnpm test:watch` |
19+
| Test (single file) | `pnpm test -- path/to/file.test.tsx` |
20+
| Type check | `pnpm typecheck` |
21+
| Lint | `pnpm lint` |
22+
| Lint + fix | `pnpm lint:fix` |
23+
| Full check before PR | `pnpm build && pnpm typecheck && pnpm lint && pnpm test` |
24+
25+
## Project Structure
26+
27+
```
28+
src/ ← core library (your focus)
29+
├── index.ts ← public API exports
30+
├── types.ts ← all TypeScript types
31+
├── context.tsx ← WebMCPProvider + useWebMCPStatus hook
32+
├── hooks/
33+
│ └── useMcpTool.ts ← main hook for tool registration
34+
├── polyfill/ ← navigator.modelContext polyfill
35+
│ ├── index.ts ← installPolyfill / cleanupPolyfill + polyfill marker
36+
│ ├── registry.ts ← in-memory tool storage
37+
│ ├── testing-shim.ts ← simulates MCP client calls
38+
│ └── validation.ts ← input validation against JSON Schema
39+
└── utils/
40+
├── schema.ts ← Zod → JSON Schema conversion + schema fingerprinting
41+
└── warn.ts ← dev-only fire-once warnings
42+
```
43+
44+
Other directories (don't modify unless explicitly asked):
45+
- `extension/` — Chrome extension that bridges web tools to desktop MCP clients
46+
- `examples/playground/` — Wordle demo showcasing dynamic tool registration
47+
- `examples/nextjs/` — Next.js integration example
48+
- `skills/` — agent skills for consumers of the library
49+
- `docs/api.md` — full API reference
50+
51+
## Architecture Decisions — Don't "Fix" These
52+
53+
These patterns look like they could be simplified but exist for specific reasons:
54+
55+
**Ownership tokens** (`TOOL_OWNER_BY_NAME` in `useMcpTool.ts`): React StrictMode double-mounts components. The ownership token ensures only the surviving mount owns the tool registration and only the owner can unregister. Removing this causes duplicate or orphaned tools.
56+
57+
**Polyfill ref-counting** (`polyfillConsumerCount` in `context.tsx`): Multiple `<WebMCPProvider>` instances can coexist. The polyfill installs on first provider mount and cleans up when the last unmounts. Don't collapse this into a simple boolean.
58+
59+
**Schema fingerprinting** (`schemaFingerprint` in `utils/schema.ts`, used by `useMcpTool.ts`): useEffect deps use string fingerprints of schemas, not object references, to prevent infinite re-registration loops when schema objects are recreated each render. Don't switch to direct object comparison.
60+
61+
**Dual execution paths**: Tools execute via `execute()` (internal/UI calls) and via the testing shim (external MCP client calls). Both paths update the same reactive state and fire the same callbacks. Changes to one path must be mirrored in the other.
62+
63+
**Ref-wrapped config** (`configRef`, `handlerRef`, etc.): Refs wrap mutable config so the registration useEffect doesn't re-run on every render. These are not missed dependencies — they're intentional stability optimizations.
64+
65+
**`"use client"` banner**: Added at build time via `tsup.config.ts`, not in source files. This makes the library work with Next.js SSR. Don't add `"use client"` to source files.
66+
67+
**Native API detection**: The polyfill checks for native `navigator.modelContext` and skips installation if it exists. Don't remove this check — Chrome is shipping native WebMCP support.
68+
69+
## Testing
70+
71+
- **Framework**: Vitest + React Testing Library + jsdom
72+
- **Location**: `__tests__/` directories adjacent to source files
73+
- **StrictMode**: All tests must pass under React StrictMode (double-mount behavior)
74+
- **Testing shim**: `polyfill/testing-shim.ts` simulates external MCP client calls — use it in tests to verify the full registration → execution → state update cycle
75+
- **Coverage areas**: Registration lifecycle, execution state, error handling, input validation, SSR safety, StrictMode compatibility
76+
77+
When adding features, write tests that cover both execution paths (direct `execute()` and testing shim `executeTool()`).
78+
79+
## Code Style
80+
81+
Biome handles formatting and linting. Pre-commit hooks run `biome check --write` on staged files — this does both formatting and linting. Unfixable lint errors will block the commit.
82+
83+
Don't manually adjust formatting — just run `pnpm lint:fix` if needed.
84+
85+
## Conventions
86+
87+
- Tool names: `snake_case` (e.g., `search_catalog`)
88+
- Tool components: PascalCase + `Tool` suffix (e.g., `SearchCatalogTool`)
89+
- Handlers return `CallToolResult` with a `content` array — always (including error results with `isError: true`)
90+
- Peer deps: React ≥ 18, React DOM ≥ 18, Zod ≥ 3. Only runtime dep is `zod-to-json-schema`
91+
- Warnings use `warnOnce()` — dev-only, fires once per key to avoid console spam
92+
93+
## Boundaries
94+
95+
- Do NOT add new dependencies without discussion
96+
- Do NOT change public API exports in `index.ts` without discussion
97+
- Do NOT remove or weaken existing tests
98+
- Do NOT add `"use client"` to source files (handled by build)
99+
- Do NOT modify `extension/`, `examples/`, or `skills/` unless asked

0 commit comments

Comments
 (0)