Jachy MCP Server
# jachy-mcp-server
Personal MCP (Model Context Protocol) server for centralized automation tools.
Provides a unified interface so nanobot, Qwen, Cursor, Claude Desktop, and other
AI agents can invoke the same set of tools through a single server.
**Current tools**
| Tool | Domain | Description |
|---|---|---|
| `discord_create_forum_post` | Discord | Creates a new post in a Discord Forum channel |
---
## Quick Start
### Prerequisites
- Node.js ≥ 22
- pnpm ≥ 9
### 1 — Install dependencies
```bash
pnpm install
# or
make install
```
### 2 — Configure environment variables
```bash
cp .env.example .env
# Open .env and fill in DISCORD_BOT_TOKEN
```
See `.env.example` for descriptions and links to obtain each value.
### 3 — Run in development mode (hot-reload)
```bash
pnpm dev
# or
make dev
```
### 4 — Build for production
```bash
pnpm build # compiles src/ → dist/
pnpm start # runs dist/index.js
# or
make build && make start
```
---
## Project Structure
```
src/
├── index.ts Entry point — validates config, creates MCP server, registers tools
├── core/
│ ├── config.ts Centralised env-var config; call validateConfig() at startup
│ └── httpClient.ts Shared fetch wrapper with retry, error formatting, request logging
├── tools/
│ ├── index.ts Single source of truth for allTools[] — only file to edit when adding a domain
│ ├── discord/
│ │ ├── index.ts Exports discordTools[]
│ │ ├── forum.ts discord_create_forum_post tool
│ │ └── helpers.ts Discord REST API helpers (private to this domain)
│ └── _template/
│ ├── index.ts Template domain index
│ ├── exampleTool.ts Template tool — copy & adapt
│ └── HOWTO.md Step-by-step guide for adding a new tool domain
└── types/
└── index.ts ToolDefinition interface and shared types
tests/
└── tools/
└── discord/
└── forum.test.ts Unit tests for discord_create_forum_post
```
---
## Adding a New Tool Domain
> Full walkthrough: [`src/tools/_template/HOWTO.md`](src/tools/_template/HOWTO.md)
**TL;DR — three steps, zero changes to `src/index.ts`:**
### Step 1 — Create your domain folder
```bash
cp -r src/tools/_template src/tools/github
mv src/tools/github/exampleTool.ts src/tools/github/createIssue.ts
```
### Step 2 — Implement your tool
Edit `createIssue.ts`:
```typescript
import { z } from 'zod';
import { type ToolDefinition } from '../../types/index.js';
import { config } from '../../core/config.js'; // ← env vars here
import { httpRequest } from '../../core/httpClient.js'; // ← HTTP here
const Schema = z.object({ repo: z.string(), title: z.string() });
export const githubCreateIssueTool: ToolDefinition = {
name: 'github_create_issue',
description: '...',
inputSchema: { type: 'object', properties: { ... }, required: ['repo', 'title'] },
handler: async (input) => {
const { repo, title } = Schema.parse(input);
// … call GitHub API …
return `Issue created: ${url}`;
},
};
```
Update `src/tools/github/index.ts`:
```typescript
import { githubCreateIssueTool } from './createIssue.js';
export const githubTools = [githubCreateIssueTool];
```
### Step 3 — Register in the global registry
Open `src/tools/index.ts` and add **one line**:
```typescript
import { githubTools } from './github/index.js';
export const allTools: ToolDefinition[] = [
...discordTools,
...githubTools, // ← add this
];
```
Done. No other file needs to change.
---
## Architecture Rules
| Rule | Why |
|---|---|
| **All env vars through `config.*`** | Single validation point; tests can override `process.env` safely |
| **All HTTP through `httpRequest()`** | Unified retry, error format, and logging |
| **Input validated with Zod in every handler** | Type safety at runtime; descriptive errors for the agent |
| **`console.log` forbidden; use `console.error`** | MCP uses stdout for JSON-RPC — any extra stdout breaks the protocol |
---
## Integrating with AI Agents
### Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"jachy-mcp-server": {
"command": "node",
"args": ["/absolute/path/to/jachy-mcp-server/dist/index.js"],
"env": {
"DISCORD_BOT_TOKEN": "your-token-here"
}
}
}
}
```
### Cursor
Add to your Cursor MCP settings (`~/.cursor/mcp.json` or workspace `.cursor/mcp.json`):
```json
{
"mcpServers": {
"jachy-mcp-server": {
"command": "node",
"args": ["/absolute/path/to/jachy-mcp-server/dist/index.js"],
"env": {
"DISCORD_BOT_TOKEN": "your-token-here"
}
}
}
}
```
### nanobot
In your nanobot config file:
```json
{
"mcp_servers": {
"jachy": {
"command": ["node", "/absolute/path/to/jachy-mcp-server/dist/index.js"],
"env": {
"DISCORD_BOT_TOKEN": "your-token-here"
}
}
}
}
```
### Using `tsx` for development (skip build step)
Replace `node dist/index.js` with `npx tsx src/index.ts` in any config above and omit the build step.
---
## Development Commands
```bash
pnpm dev # Run with hot-reload (tsx watch)
pnpm build # Compile TypeScript → dist/
pnpm start # Run compiled output
pnpm test # Run tests once (vitest)
pnpm test:watch # Run tests in watch mode
pnpm lint # ESLint
pnpm format # Prettier (writes in-place)
```
Or use `make <command>` for any of the above.
---
## Setting Up a Discord Bot
1. Go to <https://discord.com/developers/applications> and create a New Application.
2. Under **Bot**, click **Reset Token** and copy it to `DISCORD_BOT_TOKEN` in `.env`.
3. Under **OAuth2 → URL Generator**, select scope `bot` and permission `Send Messages` + `Create Public Threads`.
4. Use the generated URL to invite the bot to your server.
5. The bot must have **View Channel** + **Send Messages in Threads** permissions on the Forum channel.
6. Enable **Developer Mode** in Discord (Settings → Advanced) to right-click channels and copy their IDs.
---
## License
ISC
TDQS
Scored across 1 tool
With only one tool, there is no possibility of confusion or overlap with other tools. The tool's purpose is singular and clearly defined as creating forum posts in Discord.
Since there is only one tool, naming consistency is inherently perfect. The tool name 'discord_create_forum_post' follows a clear verb_noun pattern with a domain prefix.
A single tool is too few for a server named 'Jachy MCP Server' which implies broader functionality, likely in the Discord domain. This minimal set feels thin and incomplete for typical Discord operations.
Inferred domain is Discord forum management, but the toolset is severely incomplete—it only allows creating posts with no ability to read, update, delete, or list existing posts. This will cause agent failures for common workflows.