mirror of
https://ghfast.top/https://github.com/discourse/discourse-mcp.git
synced 2026-07-17 11:56:36 +08:00
* FEATURE: add support for topic editing - supports tagging/categorising/changing title on an existing topic - added linting * version bump * avoid uses of any where possible no new features just consistency / maintainability * - simpler agents md - improved docs - better parsing for auth pairs - clear write access checks - better testing of tool lists
94 lines
2.9 KiB
Markdown
94 lines
2.9 KiB
Markdown
# AGENTS.md — Discourse MCP
|
|
|
|
MCP server exposing Discourse forum capabilities as tools/resources for AI agents.
|
|
Entry: `src/index.ts` → `dist/index.js` (binary: `discourse-mcp`). Node >= 24.
|
|
|
|
## SDLC Commands
|
|
|
|
```bash
|
|
pnpm build # Compile TypeScript to dist/
|
|
pnpm typecheck # Type-check only (no emit)
|
|
pnpm lint # Run ESLint on src/
|
|
pnpm test # Run tests (requires build first)
|
|
pnpm clean # Remove dist/
|
|
```
|
|
|
|
## Source Map
|
|
|
|
| Area | Files |
|
|
|------|-------|
|
|
| Entry/CLI | `src/index.ts` |
|
|
| HTTP client | `src/http/client.ts` |
|
|
| Tool registry | `src/tools/registry.ts` |
|
|
| Resource registry | `src/resources/registry.ts` |
|
|
| Built-in tools | `src/tools/builtin/*` |
|
|
| Remote tools | `src/tools/remote/tool_exec_api.ts` |
|
|
| Utilities | `src/util/*.ts` (logger, redact, json_response) |
|
|
|
|
## Key Patterns
|
|
|
|
**Tool Implementation**
|
|
- Tools live in `src/tools/builtin/` as individual files
|
|
- Each tool exports a registration function called by `src/tools/registry.ts`
|
|
- All tools return strict JSON (no Markdown) with `isError: true` on failure
|
|
- Write tools require `--allow_writes` flag and matching `auth_pairs` entry
|
|
|
|
**Resources**
|
|
- URI-addressable read-only data (categories, tags, groups, channels, drafts)
|
|
- Registered in `src/resources/registry.ts`
|
|
|
|
**HTTP Layer**
|
|
- Client in `src/http/client.ts` handles auth, retries (429/5xx), caching
|
|
- User-Agent: `Discourse-MCP/0.x`
|
|
- Write tools enforce ~1 req/sec rate limit
|
|
|
|
**Configuration**
|
|
- CLI flags validated via Zod in `src/index.ts`
|
|
- Auth via `--auth_pairs` JSON (API keys or User API keys)
|
|
- `--site <url>` tethers to single site, hides `discourse_select_site` tool
|
|
|
|
**Testing**
|
|
- Tests in `src/test/` use Node's built-in test runner
|
|
- Build before running tests: `pnpm build && pnpm test`
|
|
|
|
## Adding a New Tool
|
|
|
|
1. Create `src/tools/builtin/<name>.ts`
|
|
2. Export a `RegisterFn` function
|
|
3. Import and call it in `src/tools/registry.ts`
|
|
|
|
**Minimal template:**
|
|
```typescript
|
|
import { z } from "zod";
|
|
import type { RegisterFn } from "../types.js";
|
|
import { jsonResponse, jsonError } from "../../util/json_response.js";
|
|
|
|
export const registerMyTool: RegisterFn = (server, ctx, opts) => {
|
|
if (!opts.allowWrites) return; // omit for read-only tools
|
|
|
|
server.registerTool(
|
|
"discourse_my_tool",
|
|
{
|
|
title: "My Tool",
|
|
description: "Does X. Returns JSON with Y.",
|
|
inputSchema: z.object({ id: z.number() }).shape,
|
|
},
|
|
async (args) => {
|
|
const { client } = ctx.siteState.ensureSelectedSite();
|
|
try {
|
|
const data = await client.get(`/endpoint.json`);
|
|
return jsonResponse(data);
|
|
} catch (e: any) {
|
|
return jsonError(`Failed: ${e?.message}`);
|
|
}
|
|
}
|
|
);
|
|
};
|
|
```
|
|
|
|
**Key helpers:**
|
|
- `jsonResponse(data)` — success response
|
|
- `jsonError(msg)` — error with `isError: true`
|
|
- `paginatedResponse(name, items, meta)` — for lists
|
|
- `rateLimit(key)` — throttle writes (call before mutations)
|
|
- `ctx.siteState.ensureSelectedSite()` — get `{ base, client }`
|