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
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ The default import stays small. Add the other pieces only when that screen needs
| 📡 Schedules | `@crup/react-timer-hook/schedules` | Polling, cadence callbacks, overdue timing context | 8.62 kB | 3.02 kB | 2.78 kB |
| 🧩 Duration | `@crup/react-timer-hook/duration` | `days`, `hours`, `minutes`, `seconds`, `milliseconds` | 318 B | 224 B | 192 B |
| 🔎 Diagnostics | `@crup/react-timer-hook/diagnostics` | Optional lifecycle and schedule event logging | 105 B | 115 B | 90 B |
| 🤖 MCP docs server | `react-timer-hook-mcp` | Optional local docs context for MCP clients and coding agents | 6.69 kB | 2.60 kB | 2.25 kB |
| 🤖 MCP docs server | `react-timer-hook-mcp` | Optional local docs context for MCP clients and coding agents | 6.95 kB | 2.72 kB | 2.36 kB |

CI writes a size summary to the GitHub Actions UI and posts bundle-size reports on pull requests.

Expand Down Expand Up @@ -308,11 +308,11 @@ react-timer-hook://recipes

It also exposes MCP tools that editors are more likely to call directly:

```txt
get_api_docs
get_recipe
search_docs
```
| Tool | Title | Description |
| --- | --- | --- |
| `get_api_docs` | Get API docs | Returns compact API notes for `@crup/react-timer-hook`. |
| `get_recipe` | Get recipe | Returns guidance for a named recipe or use case. |
| `search_docs` | Search docs | Searches API and recipe notes for a query. |

## Contributing

Expand Down
10 changes: 5 additions & 5 deletions docs-site/docs/ai.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ react-timer-hook://recipes

It also exposes callable tools for MCP clients that prefer tool calls over resource reads:

```txt
get_api_docs
get_recipe
search_docs
```
| Tool | Title | Description |
| --- | --- | --- |
| `get_api_docs` | Get API docs | Returns compact API notes for `@crup/react-timer-hook`. |
| `get_recipe` | Get recipe | Returns guidance for a named recipe or use case. |
| `search_docs` | Search docs | Searches API and recipe notes for a query. |

Verify locally:

Expand Down
6 changes: 3 additions & 3 deletions docs-site/static/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ Local docs MCP server:
The package bundles the MCP server at node_modules/@crup/react-timer-hook/dist/mcp/server.js and exposes it through the react-timer-hook-mcp bin.

MCP tools:
- get_api_docs
- get_recipe
- search_docs
- get_api_docs: Get API docs. Returns compact API notes for @crup/react-timer-hook.
- get_recipe: Get recipe. Returns guidance for a named recipe or use case.
- search_docs: Search docs. Searches API and recipe notes for a query.

## Boundaries

Expand Down
21 changes: 20 additions & 1 deletion mcp/server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ const recipes = {
const tools = [
{
name: 'get_api_docs',
title: 'Get API docs',
description: 'Return the compact API notes for @crup/react-timer-hook.',
inputSchema: {
type: 'object',
Expand All @@ -103,6 +104,7 @@ const tools = [
},
{
name: 'get_recipe',
title: 'Get recipe',
description: 'Return guidance for a named recipe or use case.',
inputSchema: {
type: 'object',
Expand All @@ -118,6 +120,7 @@ const tools = [
},
{
name: 'search_docs',
title: 'Search docs',
description: 'Search API and recipe notes for a query.',
inputSchema: {
type: 'object',
Expand Down Expand Up @@ -146,6 +149,12 @@ rl.on('line', line => {
}

const { id, method, params } = request;
const hasId = Object.hasOwn(request, 'id');

if (!method) {
if (hasId) respondError(id, -32600, 'Invalid request: missing method.');
return;
}

if (method === 'initialize') {
respond(id, {
Expand All @@ -156,6 +165,15 @@ rl.on('line', line => {
return;
}

if (method === 'notifications/initialized' || method.startsWith('notifications/')) {
return;
}

if (method === 'ping') {
if (hasId) respond(id, {});
return;
}

if (method === 'resources/list') {
respond(id, {
resources: Object.entries(resources).map(([uri, resource]) => ({
Expand Down Expand Up @@ -231,7 +249,7 @@ rl.on('line', line => {
return;
}

respondError(id, -32601, `Method not found: ${method}`);
if (hasId) respondError(id, -32601, `Method not found: ${method}`);
});

function respond(id, result) {
Expand All @@ -243,6 +261,7 @@ function respondTool(id, text) {
}

function respondError(id, code, message) {
if (id === undefined) return;
process.stdout.write(`${JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } })}\n`);
}

Expand Down
6 changes: 5 additions & 1 deletion scripts/check-mcp-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ child.stderr.on('data', chunk => {
child.stdin.end(
[
JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }),
JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized', params: {} }),
JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'resources/list', params: {} }),
JSON.stringify({
jsonrpc: '2.0',
Expand Down Expand Up @@ -86,7 +87,10 @@ child.on('close', code => {
process.exit(1);
}

if (!tools.some(tool => tool.name === 'get_recipe') || !tools.some(tool => tool.name === 'search_docs')) {
if (
!tools.some(tool => tool.name === 'get_recipe' && tool.title === 'Get recipe') ||
!tools.some(tool => tool.name === 'search_docs' && tool.title === 'Search docs')
) {
console.error('MCP tools list is missing expected docs tools.');
process.exit(1);
}
Expand Down
Loading