{
  "markdown": "# pls-touch-grass-mcp\n\n[![npm](https://img.shields.io/npm/v/pls-touch-grass-mcp)](https://www.npmjs.com/package/pls-touch-grass-mcp)\n[![ci](https://github.com/Rinava/pls-touch-grass-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/Rinava/pls-touch-grass-mcp/actions/workflows/ci.yml)\n[![license: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)\n\nAn MCP server that knows how long it's been since you touched grass, and won't shut up about it.\n\nYou log grass, it tracks indoor time, it catches you raging at your AI and sends you\nto the nearest park, weather checked first. A joke, but one that teaches MCP: five\ntools, shared state, and descriptions that make the model call them unprompted.\n\n## Install\n\n### Claude Code\n\n```bash\nclaude mcp add pls-touch-grass -s user -- npx -y pls-touch-grass-mcp\n```\n\n`-s user`, or the server only exists in the directory you ran that from. Working from\na clone, skip the command: there's a `.mcp.json` in the root and Claude Code offers it\nwhen you open the folder.\n\n### Cursor\n\n[![Add to Cursor](https://img.shields.io/badge/Add_to-Cursor-000000?style=for-the-badge)](https://cursor.com/install-mcp?name=pls-touch-grass&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBscy10b3VjaC1ncmFzcy1tY3AiXX0=)\n\nOr the JSON, in `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per project):\n\n```json\n{\n  \"mcpServers\": {\n    \"pls-touch-grass\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"pls-touch-grass-mcp\"]\n    }\n  }\n}\n```\n\n### Claude Desktop\n\n`.mcpb` from [Releases](https://github.com/Rinava/pls-touch-grass-mcp/releases), then\nSettings → Extensions → Install Extension. Dependencies are bundled; installs offline.\nBy hand it's the same JSON as Cursor, in `claude_desktop_config.json`\n(`~/Library/Application Support/Claude/` on macOS, `%APPDATA%\\Claude\\` on Windows).\n\n### claude.ai\n\nNo. Custom connectors want a remote server over HTTPS; this is stdio on your own\nmachine. HTTP transport is the first item under [Homework](#homework).\n\n### From source\n\n```bash\ngit clone https://github.com/Rinava/pls-touch-grass-mcp\ncd pls-touch-grass-mcp\nnpm ci && npm run build\n```\n\nPoint any config above at `node /absolute/path/to/dist/index.js` instead.\n\n`npx -y` downloads the package on first start — live audiences and venue wifi deserve\na warm cache. Published on npm as `pls-touch-grass-mcp`, in the MCP Registry as\n`io.github.Rinava/pls-touch-grass`.\n\n## The five tools\n\n| Tool | What it does | When the model calls it |\n|------|--------------|-------------------------|\n| `touched_grass` | Logs that you went outside | \"back from the park\" |\n| `gotta_go` | Do you need to go out? | \"can I keep going?\" |\n| `frustration_detector` | Catches the rage and escalates | on its own, when you snap; that's the point |\n| `grass_conditions` | Real weather (Open-Meteo, no key) | before sending you outside |\n| `where_to_touch_grass` | Nearby parks with distances (OpenStreetMap) | \"where should I go?\", or when you name a place |\n\nNobody teaches the model to detect frustration: the tool description does it alone.\nType \"NOTHING WORKS!!!\" and watch.\n\n## Zero configuration\n\nLocation resolves fresh from your IP ([ipwho.is](https://ipwho.is)) each run —\ncity-level on purpose. Detection down: last known spot, then the Obelisco, like\neveryone else. Name a neighborhood or a street address to `where_to_touch_grass` and\nit sticks: known neighborhoods resolve offline, anything else is geocoded once through\nOpenStreetMap's Nominatim, and only the words you typed leave your machine. A place\nyou named outranks a guess from your IP, until you name a different one.\n\nIndoor tolerance defaults to a merciless 2 minutes; ask the model for clemency and it\npasses a bigger `threshold_minutes` to `gotta_go`. State is one JSON file,\n`~/.pls-touch-grass.json`. Touching grass resets the rage counter. That's how\nabsolution works.\n\n## The demo curse\n\nLive demos summon it: the venue wifi dies the moment you say \"watch this\". Add\n`--demo` to the `args` and every answer goes canned — 22°C and clear, the Obelisco,\nthe curated spots. Zero network calls, zero surprises. Off by default; real life\nshould stay real.\n\n## Follow the workshop\n\nThe repo is tagged by step:\n\n```bash\ngit checkout step-1   # stdio server + touched_grass\ngit checkout step-2   # + gotta_go (state and threshold)\ngit checkout step-3   # + frustration_detector (the demo)\ngit checkout step-4   # + grass_conditions (network with fallback)\ngit checkout step-5   # + where_to_touch_grass and this README\nnpm ci && npm test\n```\n\nEvery step compiles and passes its own tests. Two dependencies total: the official\nMCP SDK and zod.\n\n## Homework\n\n- HTTP transport: `createMcpHandler` in SDK v2 serves the same factory over fetch, and it's what gets you onto claude.ai\n- Per-project thresholds instead of a global one\n- Streak tracking for consecutive grass days\n- Demo spots for your own city, via PR: one object per park in `src/lib/demo.ts`, with an opinion\n\n## Release\n\n`npm run build:mcpb` packs `dist` and the production dependencies into\n`pls-touch-grass-mcp-<version>.mcpb`, the file that goes on a GitHub Release. The\nmanifest is generated from `package.json`; nothing to keep in sync by hand.\n\n## Contributing\n\nIssues and PRs welcome — the [Homework](#homework) list is seeded as\n[open issues](https://github.com/Rinava/pls-touch-grass-mcp/issues), several\ntagged `good first issue`. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and\nthe house rules (there are few, but the demo-spot opinion is mandatory).\n\n## License\n\nMIT. The grass is free and so is this.\n",
  "bytes": 5577,
  "sha": "97f5f9545d8ccf13b449a3a3f690363d557e299d8dd6e15ad1226a16f17a9fb1",
  "repo_slug": "rinava/pls-touch-grass-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_rinava_pls_touch_grass_28eff748/readme"
}