Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/http/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Provides Fastify-based HTTP transport for the MCP protocol. Handles SSE streams,

- **FastifyTransport** (`FastifyTransport.ts`) — Main HTTP transport. Per-client bundles via ClientResourceCache, optional SessionContextResolver for context differentiation.
- **Origin validation** (`originValidation.ts`) — `normalizeAllowedOrigins()` + `createOriginGuard()`; each transport applies the guard as an `onRequest` hook on `/mcp` POST/GET/DELETE only, when `allowedOrigins` is set.
- **Custom Endpoints** (`customEndpoints.ts`, `endpointRegistration.ts`) — Type-safe endpoint definitions with Zod schemas. `defineEndpoint()` / `definePermissionAwareEndpoint()` helpers.
- **Custom Endpoints** (`http.utils.ts`, types in `http.types.ts`) — Type-safe endpoint definitions with Zod 4 schemas. `defineEndpoint()` / `definePermissionAwareEndpoint()` helpers build them; `registerCustomEndpoints()` mounts them and enforces the reserved paths. Validation failures answer 400 `VALIDATION_ERROR` with Zod 4 issues in `error.details`.

## Endpoints

Expand Down
4 changes: 2 additions & 2 deletions src/meta/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ Registers meta-tools on MCP servers for runtime toolset management. Called by Se

## Invariants

1. **`_meta` is a reserved toolset key** — If a catalog uses `"_meta"` as a toolset key, ToolRegistry will detect a name collision at registration time. Never use this key in the catalog.
1. **`_meta` is a reserved toolset key** — `RESERVED_TOOLSET_KEYS` (`src/mode/mode.types.ts`) makes the `ModuleResolver` constructor throw when a catalog has a `"_meta"` key, and `validateToolsetName()` also refuses it ("reserved for internal use"). Never use this key in the catalog.
2. **Meta-tools registered via ToolRegistry** — Same collision detection path as user tools. Meta-tools appear in `toolRegistry.list()` and `toolRegistry.listByToolset()`.
3. **`enable_toolset` / `disable_toolset` annotated with `destructiveHint: false, idempotentHint: true`** — They change which tools are exposed but destroy nothing, and repeating either call has no further effect on state. Visible to LLM clients via MCP tool annotations. Discovery tools (`list_*`, `describe_*`) use `readOnlyHint: true`.

## Anti-patterns

- Using `_meta` as a catalog key (collision with meta-tools)
- Using `_meta` as a catalog key (the resolver throws at construction)
- Registering meta-tools outside of `registerMetaTools()` (bypasses ToolRegistry)
- Expecting meta-tools in permission-based servers (they are never registered — `registerMetaTools(false)`)

Expand Down
14 changes: 8 additions & 6 deletions src/mode/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ Handles toolset resolution, validation, and module loading. Bridges toolset defi
## Key Components

- **ModuleResolver** (`ModuleResolver.ts`) — Stores catalog, validates toolset names, resolves tools by collecting direct tools + calling module loaders.
- **moduleLoading.ts** — empty placeholder: no code, nothing imports it.
- **ToolsetValidator** (`ModeResolver.ts`) — Validates toolset names against a provided catalog, parses comma-separated toolset strings. Also resolves startup mode from env/args.

## Invariants

1. **Module loaders fail silently** — Errors caught, logged as warnings, skipped. Toolset activates with whatever tools succeeded. This is intentional — one broken loader should not block the rest.
2. **ToolsetValidator is in ModeResolver.ts** — Historical naming quirk. `ToolsetValidator.ts` just re-exports from `ModeResolver.ts`. Import from either file.
3. **ModuleResolver stores catalog; ToolsetValidator takes it as parameter** — Different validation signatures. ModuleResolver validates against its stored catalog; ToolsetValidator is stateless.
4. **Context passed to module loaders** — Enables dynamic tool generation based on runtime context (e.g., per-client tools).
1. **`_meta` is rejected** — `RESERVED_TOOLSET_KEYS` (`mode.types.ts`): the `ModuleResolver` constructor throws if the catalog has such a key, and `validateToolsetName()` refuses it again as defense in depth.
2. **Module loaders fail silently** — Errors caught, logged as warnings, skipped. Toolset activates with whatever tools succeeded. This is intentional — one broken loader should not block the rest.
3. **ToolsetValidator is in ModeResolver.ts** — Historical naming quirk. `ToolsetValidator.ts` just re-exports from `ModeResolver.ts`. Import from either file.
4. **ModuleResolver stores catalog; ToolsetValidator takes it as parameter** — Different validation signatures. ModuleResolver validates against its stored catalog; ToolsetValidator is stateless.
5. **Context passed to module loaders** — Enables dynamic tool generation based on runtime context (e.g., per-client tools).

## Module Loading Flow

Expand All @@ -25,14 +27,14 @@ resolveToolsForToolsets([toolsetName], context)
2. For each module in definition.modules[]:
→ Look up loader in moduleLoaders map
→ Call loader(context) — may be async
→ Catch errors → warn and skip (invariant #1)
→ Catch errors → warn and skip (invariant #2)
→ Append returned tools
Return flattened McpToolDefinition[]
```

## Anti-patterns

- Throwing on invalid toolset names (return validation result instead)
- Throwing on invalid toolset names at runtime (return a validation result instead; only a reserved key in the catalog throws, at construction)
- Assuming module loaders are synchronous (always await)
- Using `ToolsetValidator.ts` directly when `ModeResolver.ts` is clearer

Expand Down
2 changes: 1 addition & 1 deletion src/session/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Manages per-session context resolution and client resource caching. Enables mult

1. **Fail-secure parsing** — Invalid base64/JSON encoding returns `{}`, not an error. Malformed client input never crashes the server.
2. **Disallowed keys silently filtered** — No logging to prevent information leakage about what keys exist.
3. **Cache key includes context hash** — Format: `${clientId}:${sha256suffix}`. Uses SHA-256 of sorted config keys — property order does not affect the hash.
3. **Cache key includes context hash** — Format: `${clientId}:${sha256suffix}`, built by the transport's `resolveSessionContext()`. When the resolver returns the suffix `"default"` (`enabled: false`; no usable `?config=`, meaning absent, malformed or empty after filtering; or a throwing `contextResolver`) the key is the plain `clientId`. The suffix is SHA-256 (first 16 hex chars) of the filtered config as JSON, top-level keys sorted — the values are part of the hash, property order is not.
4. **LRU eviction triggers cleanup** — onEvict callback called on removal. Transport uses this to close all sessions in an evicted bundle.
5. **Background pruning interval** — Removes TTL-expired entries periodically. `stop(true)` clears all entries and triggers cleanup.

Expand Down
Loading