@outfitter/presets 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/package.json +2 -2
  2. package/presets/_base/AGENTS.md.template +3 -0
  3. package/presets/_base/CLAUDE.md.template +35 -0
  4. package/presets/_examples/cli-todo/src/program.ts.template +202 -0
  5. package/presets/_examples/mcp-files/src/mcp.ts.template +181 -0
  6. package/presets/basic/README.md.template +22 -0
  7. package/presets/basic/package.json.template +41 -37
  8. package/presets/basic/src/index.test.ts.template +26 -0
  9. package/presets/basic/src/index.ts.template +32 -15
  10. package/presets/basic/tsconfig.json.template +28 -29
  11. package/presets/cli/CLAUDE.md.template +60 -0
  12. package/presets/cli/README.md.template +5 -1
  13. package/presets/cli/package.json.template +47 -44
  14. package/presets/cli/src/commands/hello.ts.template +26 -0
  15. package/presets/cli/src/index.test.ts.template +38 -0
  16. package/presets/cli/src/index.ts.template +2 -0
  17. package/presets/cli/src/program.ts.template +17 -19
  18. package/presets/cli/src/types.ts.template +13 -0
  19. package/presets/cli/tsconfig.json.template +29 -29
  20. package/presets/daemon/CLAUDE.md.template +53 -0
  21. package/presets/daemon/README.md.template +6 -7
  22. package/presets/daemon/package.json.template +50 -47
  23. package/presets/daemon/src/cli.ts.template +73 -66
  24. package/presets/daemon/src/daemon-main.ts.template +56 -55
  25. package/presets/daemon/src/daemon.ts.template +7 -3
  26. package/presets/daemon/src/index.test.ts.template +9 -0
  27. package/presets/daemon/tsconfig.json.template +21 -21
  28. package/presets/full-stack/CLAUDE.md.template +66 -0
  29. package/presets/full-stack/apps/cli/package.json.template +34 -33
  30. package/presets/full-stack/apps/cli/src/cli.ts.template +16 -15
  31. package/presets/full-stack/apps/cli/src/index.test.ts.template +12 -11
  32. package/presets/full-stack/apps/cli/tsconfig.json.template +32 -32
  33. package/presets/full-stack/apps/mcp/package.json.template +35 -34
  34. package/presets/full-stack/apps/mcp/src/index.test.ts.template +12 -11
  35. package/presets/full-stack/apps/mcp/src/mcp.ts.template +10 -10
  36. package/presets/full-stack/apps/mcp/src/server.ts.template +3 -2
  37. package/presets/full-stack/apps/mcp/tsconfig.json.template +32 -32
  38. package/presets/full-stack/package.json.template +20 -14
  39. package/presets/full-stack/packages/core/package.json.template +31 -30
  40. package/presets/full-stack/packages/core/src/handlers.ts.template +29 -24
  41. package/presets/full-stack/packages/core/src/index.test.ts.template +23 -21
  42. package/presets/full-stack/packages/core/src/types.ts.template +11 -8
  43. package/presets/full-stack/packages/core/tsconfig.json.template +29 -29
  44. package/presets/library/CLAUDE.md.template +68 -0
  45. package/presets/library/bunup.config.ts.template +16 -16
  46. package/presets/library/package.json.template +51 -50
  47. package/presets/library/src/handlers.ts.template +51 -27
  48. package/presets/library/src/index.test.ts.template +40 -29
  49. package/presets/library/src/types.ts.template +14 -8
  50. package/presets/library/tsconfig.json.template +29 -29
  51. package/presets/mcp/CLAUDE.md.template +97 -0
  52. package/presets/mcp/README.md.template +12 -9
  53. package/presets/mcp/package.json.template +48 -44
  54. package/presets/mcp/src/index.test.ts.template +49 -0
  55. package/presets/mcp/src/index.ts.template +2 -0
  56. package/presets/mcp/src/mcp.ts.template +16 -16
  57. package/presets/mcp/src/server.ts.template +8 -1
  58. package/presets/mcp/src/tools/hello.ts.template +48 -0
  59. package/presets/mcp/tsconfig.json.template +21 -21
  60. package/presets/minimal/README.md.template +22 -0
  61. package/presets/minimal/package.json.template +47 -44
  62. package/presets/minimal/src/index.test.ts.template +19 -0
  63. package/presets/minimal/src/index.ts.template +10 -15
  64. package/presets/minimal/tsconfig.json.template +28 -29
@@ -0,0 +1,68 @@
1
+ # CLAUDE.md
2
+
3
+ Bun-first TypeScript library. Tests before code. Result types, not exceptions.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ bun run build # Build library with bunup (ESM + types)
9
+ bun run dev # Watch mode
10
+ bun run test # Run tests
11
+ bun run typecheck # TypeScript validation
12
+ bun run check # Lint + format check (ultracite)
13
+ bun run lint # Lint checks (oxlint)
14
+ bun run lint:fix # Auto-fix lint issues
15
+ bun run format # Auto-fix formatting (oxfmt)
16
+ bun run verify:ci # Full CI validation (typecheck + check + build + test)
17
+ ```
18
+
19
+ ## Architecture
20
+
21
+ Publishable TypeScript library built with Bun and bunup.
22
+
23
+ ### Project Structure
24
+
25
+ - `src/types.ts` — Zod schemas with explicit `ZodType` annotations + TypeScript interfaces
26
+ - `src/handlers.ts` — Pure handler functions returning `Result<T, E>`
27
+ - `src/index.ts` — Re-exports from types + handlers
28
+ - `src/index.test.ts` — Tests with `createContext()`, testing success + error paths
29
+
30
+ ### Handler Contract
31
+
32
+ All domain logic uses transport-agnostic handlers returning `Result<T, E>`:
33
+
34
+ ```typescript
35
+ async function handler(
36
+ input: unknown,
37
+ ctx: HandlerContext
38
+ ): Promise<Result<Output, ValidationError>> {
39
+ const parsed = inputSchema.safeParse(input);
40
+ if (!parsed.success) {
41
+ return Result.err(new ValidationError({ message: "...", field: "name" }));
42
+ }
43
+ // business logic
44
+ return Result.ok(result);
45
+ }
46
+ ```
47
+
48
+ ### Schema Convention
49
+
50
+ Exported Zod schemas must have explicit type annotations:
51
+
52
+ ```typescript
53
+ export const inputSchema: ZodType<Input> = z.object({ ... });
54
+ ```
55
+
56
+ ## Development Principles
57
+
58
+ - **TDD-First** — Write the test before the code (Red / Green / Refactor)
59
+ - **Result Types** — Handlers return `Result<T, E>`, not exceptions
60
+ - **Bun-First** — Use Bun-native APIs before npm packages
61
+ - **Strict TypeScript** — No `any`, no `as` casts; narrow instead of assert
62
+
63
+ ## Testing
64
+
65
+ - Runner: Bun test runner
66
+ - Files: `src/*.test.ts`
67
+ - Run: `bun test` or `bun run test`
68
+ - Test handlers with `createContext()` from `@outfitter/contracts`
@@ -1,20 +1,20 @@
1
1
  import { defineWorkspace } from "bunup";
2
2
 
3
3
  export default defineWorkspace(
4
- [
5
- {
6
- name: "{{packageName}}",
7
- root: ".",
8
- },
9
- ],
10
- {
11
- entry: ["src/**/*.ts", "!src/**/*.test.ts", "!src/**/__tests__/**"],
12
- sourceBase: "./src",
13
- format: ["esm", "cjs"],
14
- dts: true,
15
- exports: true,
16
- splitting: true,
17
- clean: true,
18
- target: "bun",
19
- }
4
+ [
5
+ {
6
+ name: "{{packageName}}",
7
+ root: ".",
8
+ },
9
+ ],
10
+ {
11
+ entry: ["src/**/*.ts", "!src/**/*.test.ts", "!src/**/__tests__/**"],
12
+ sourceBase: "./src",
13
+ format: ["esm", "cjs"],
14
+ dts: true,
15
+ exports: true,
16
+ splitting: true,
17
+ clean: true,
18
+ target: "bun",
19
+ }
20
20
  );
@@ -1,52 +1,53 @@
1
1
  {
2
- "name": "{{packageName}}",
3
- "version": "{{version}}",
4
- "description": "{{description}}",
5
- "type": "module",
6
- "main": "./dist/index.cjs",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "files": [
10
- "dist"
11
- ],
12
- "sideEffects": false,
13
- "exports": {
14
- ".": {
15
- "types": "./dist/index.d.ts",
16
- "import": "./dist/index.js",
17
- "require": "./dist/index.cjs"
18
- }
19
- },
20
- "scripts": {
21
- "build": "bunup",
22
- "dev": "bun --watch src/index.ts",
23
- "test": "bun test",
24
- "test:watch": "bun test --watch",
25
- "typecheck": "tsc --noEmit",
26
- "lint": "oxlint .",
27
- "lint:fix": "oxlint --fix .",
28
- "format": "oxfmt --write .",
29
- "clean:artifacts": "rm -rf dist .turbo",
30
- "clean": "rm -rf dist"
31
- },
32
- "dependencies": {
33
- "@outfitter/contracts": "workspace:*",
34
- "@outfitter/logging": "workspace:*",
35
- "zod": "^4.3.5"
36
- },
37
- "devDependencies": {
38
- "bunup": "^0.16.29"
39
- },
40
- "outfitter": {
41
- "template": {
42
- "kind": "library",
43
- "placement": "packages",
44
- "surfaces": []
45
- }
46
- },
47
- "engines": {
48
- "bun": ">=1.3.10"
49
- },
50
- "keywords": [],
51
- "license": "MIT"
2
+ "name": "{{packageName}}",
3
+ "version": "{{version}}",
4
+ "description": "{{description}}",
5
+ "keywords": [],
6
+ "license": "MIT",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "type": "module",
11
+ "sideEffects": false,
12
+ "main": "./dist/index.cjs",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "require": "./dist/index.cjs"
20
+ }
21
+ },
22
+ "scripts": {
23
+ "build": "bunup",
24
+ "dev": "bun --watch src/index.ts",
25
+ "test": "bun test",
26
+ "test:watch": "bun test --watch",
27
+ "typecheck": "tsc --noEmit",
28
+ "check": "ultracite check",
29
+ "lint": "oxlint .",
30
+ "lint:fix": "oxlint --fix .",
31
+ "format": "oxfmt --write .",
32
+ "verify:ci": "bun run typecheck && bun run check && bun run build && bun run test",
33
+ "clean:artifacts": "rm -rf dist .turbo",
34
+ "clean": "rm -rf dist"
35
+ },
36
+ "dependencies": {
37
+ "@outfitter/contracts": "workspace:*",
38
+ "zod": "catalog:"
39
+ },
40
+ "devDependencies": {
41
+ "bunup": "catalog:"
42
+ },
43
+ "engines": {
44
+ "bun": ">=1.3.10"
45
+ },
46
+ "outfitter": {
47
+ "template": {
48
+ "kind": "library",
49
+ "placement": "packages",
50
+ "surfaces": []
51
+ }
52
+ }
52
53
  }
@@ -1,31 +1,55 @@
1
- import { Result, ValidationError, type Handler } from "@outfitter/contracts";
2
- import { createLogger } from "@outfitter/logging";
3
- import { greetingInputSchema, type Greeting } from "./types.js";
1
+ import {
2
+ Result,
3
+ ValidationError,
4
+ type HandlerContext,
5
+ } from "@outfitter/contracts";
4
6
 
5
- const logger = createLogger({ name: "{{projectName}}" });
7
+ import { greetingInputSchema, type Greeting } from "./types.js";
6
8
 
7
- export const createGreeting: Handler<unknown, Greeting, ValidationError> = async (
8
- input,
9
- ctx
10
- ) => {
11
- const parsed = greetingInputSchema.safeParse(input);
12
- if (!parsed.success) {
13
- return Result.err(
14
- new ValidationError({
15
- message: "Invalid greeting input",
16
- field: "name",
17
- })
18
- );
19
- }
9
+ /**
10
+ * Create a greeting from unvalidated input.
11
+ *
12
+ * @param input - Raw input to validate against {@link greetingInputSchema}
13
+ * @param ctx - Handler context with logger and request metadata
14
+ * @returns Validated greeting or a `ValidationError` with field-level validation details
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const result = await createGreeting({ name: "World" }, ctx);
19
+ * if (result.isOk()) {
20
+ * console.log(result.value.message); // "Hello, World."
21
+ * }
22
+ * ```
23
+ */
24
+ export async function createGreeting(
25
+ input: unknown,
26
+ ctx: HandlerContext
27
+ ): Promise<Result<Greeting, ValidationError>> {
28
+ const parsed = greetingInputSchema.safeParse(input);
29
+ if (!parsed.success) {
30
+ const issue = parsed.error.issues[0];
31
+ return Result.err(
32
+ new ValidationError({
33
+ message: issue?.message ?? "Invalid greeting input",
34
+ field: issue?.path.join(".") || "input",
35
+ context: {
36
+ fields: parsed.error.issues.map((i) => ({
37
+ path: i.path.join(".") || "input",
38
+ message: i.message,
39
+ })),
40
+ },
41
+ })
42
+ );
43
+ }
20
44
 
21
- const suffix = parsed.data.excited ? "!" : ".";
22
- const greeting: Greeting = {
23
- message: `Hello, ${parsed.data.name}${suffix}`,
24
- issuedAt: new Date().toISOString(),
25
- };
45
+ const suffix = parsed.data.excited ? "!" : ".";
46
+ const greeting: Greeting = {
47
+ message: `Hello, ${parsed.data.name}${suffix}`,
48
+ issuedAt: new Date().toISOString(),
49
+ };
26
50
 
27
- logger.info(`Created greeting for ${parsed.data.name}`, {
28
- requestId: ctx.requestId,
29
- });
30
- return Result.ok(greeting);
31
- };
51
+ ctx.logger.info(`Created greeting for ${parsed.data.name}`, {
52
+ requestId: ctx.requestId,
53
+ });
54
+ return Result.ok(greeting);
55
+ }
@@ -1,35 +1,46 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+
2
3
  import { createContext } from "@outfitter/contracts";
4
+
3
5
  import { createGreeting } from "./handlers.js";
4
6
 
5
7
  describe("createGreeting", () => {
6
- test("returns greeting for valid input", async () => {
7
- const ctx = createContext({
8
- cwd: process.cwd(),
9
- env: process.env,
10
- });
11
- const result = await createGreeting(
12
- { name: "Outfitter", excited: true },
13
- ctx
14
- );
15
-
16
- expect(result.isOk()).toBe(true);
17
- if (result.isErr()) {
18
- return;
19
- }
20
- expect(result.value.message).toBe("Hello, Outfitter!");
21
- });
22
-
23
- test("returns validation error for invalid input", async () => {
24
- const ctx = createContext({
25
- cwd: process.cwd(),
26
- env: process.env,
27
- });
28
- const result = await createGreeting({ name: "" }, ctx);
29
-
30
- expect(result.isErr()).toBe(true);
31
- if (result.isErr()) {
32
- expect(result.error.name).toBe("ValidationError");
33
- }
34
- });
8
+ const ctx = createContext({ cwd: process.cwd(), env: process.env });
9
+
10
+ test("returns greeting for valid input", async () => {
11
+ const result = await createGreeting(
12
+ { name: "Outfitter", excited: true },
13
+ ctx
14
+ );
15
+
16
+ expect(result.isOk()).toBe(true);
17
+ if (result.isErr()) return;
18
+ expect(result.value.message).toBe("Hello, Outfitter!");
19
+ });
20
+
21
+ test("returns validation error for empty name", async () => {
22
+ const result = await createGreeting({ name: "" }, ctx);
23
+
24
+ expect(result.isErr()).toBe(true);
25
+ if (!result.isErr()) return;
26
+ expect(result.error.name).toBe("ValidationError");
27
+ expect(result.error.message).toBe("name is required");
28
+ expect(result.error.context).toEqual({
29
+ fields: [{ path: "name", message: "name is required" }],
30
+ });
31
+ });
32
+
33
+ test("returns validation error for missing input", async () => {
34
+ const result = await createGreeting({}, ctx);
35
+
36
+ expect(result.isErr()).toBe(true);
37
+ if (!result.isErr()) return;
38
+ expect(result.error.name).toBe("ValidationError");
39
+ // Check error field rather than message text — Zod error messages
40
+ // differ between v3 ("Required") and v4 ("Invalid input: ...").
41
+ const fields = result.error.context?.fields as
42
+ | Array<{ path: string }>
43
+ | undefined;
44
+ expect(fields?.some((f) => f.path === "name")).toBe(true);
45
+ });
35
46
  });
@@ -1,13 +1,19 @@
1
- import { z } from "zod";
1
+ import { type ZodType, z } from "zod";
2
2
 
3
- export const greetingInputSchema = z.object({
4
- name: z.string().min(1, "name is required"),
5
- excited: z.boolean().default(false),
6
- });
3
+ /** Input for the greeting handler. */
4
+ export interface GreetingInput {
5
+ readonly name: string;
6
+ readonly excited: boolean;
7
+ }
7
8
 
8
- export type GreetingInput = z.infer<typeof greetingInputSchema>;
9
+ /** Zod schema for validating greeting input at the boundary. */
10
+ export const greetingInputSchema: ZodType<GreetingInput> = z.object({
11
+ name: z.string().min(1, "name is required"),
12
+ excited: z.boolean().default(false),
13
+ });
9
14
 
15
+ /** A generated greeting with timestamp. */
10
16
  export interface Greeting {
11
- readonly message: string;
12
- readonly issuedAt: string;
17
+ readonly message: string;
18
+ readonly issuedAt: string;
13
19
  }
@@ -1,34 +1,34 @@
1
1
  {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "compilerOptions": {
4
- "target": "ESNext",
5
- "module": "ESNext",
6
- "moduleResolution": "bundler",
7
- "lib": ["ESNext"],
8
- "types": ["@types/bun"],
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ "target": "ESNext",
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "lib": ["ESNext"],
8
+ "types": ["@types/bun"],
9
9
 
10
- "strict": true,
11
- "noImplicitAny": true,
12
- "strictNullChecks": true,
13
- "noUncheckedIndexedAccess": true,
14
- "exactOptionalPropertyTypes": true,
15
- "noPropertyAccessFromIndexSignature": true,
16
- "noImplicitReturns": true,
17
- "noFallthroughCasesInSwitch": true,
10
+ "strict": true,
11
+ "noImplicitAny": true,
12
+ "strictNullChecks": true,
13
+ "noUncheckedIndexedAccess": true,
14
+ "exactOptionalPropertyTypes": true,
15
+ "noPropertyAccessFromIndexSignature": true,
16
+ "noImplicitReturns": true,
17
+ "noFallthroughCasesInSwitch": true,
18
18
 
19
- "declaration": true,
20
- "declarationMap": true,
21
- "sourceMap": true,
22
- "outDir": "./dist",
23
- "rootDir": "./src",
19
+ "declaration": true,
20
+ "declarationMap": true,
21
+ "sourceMap": true,
22
+ "outDir": "./dist",
23
+ "rootDir": "./src",
24
24
 
25
- "esModuleInterop": true,
26
- "forceConsistentCasingInFileNames": true,
27
- "isolatedModules": true,
28
- "verbatimModuleSyntax": true,
29
- "skipLibCheck": true,
30
- "resolveJsonModule": true
31
- },
32
- "include": ["src/**/*"],
33
- "exclude": ["node_modules", "dist"]
25
+ "esModuleInterop": true,
26
+ "forceConsistentCasingInFileNames": true,
27
+ "isolatedModules": true,
28
+ "verbatimModuleSyntax": true,
29
+ "skipLibCheck": true,
30
+ "resolveJsonModule": true
31
+ },
32
+ "include": ["src/**/*"],
33
+ "exclude": ["node_modules", "dist"]
34
34
  }
@@ -0,0 +1,97 @@
1
+ # CLAUDE.md
2
+
3
+ Bun-first TypeScript MCP server. Tests before code. Result types, not exceptions.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ bun run build # Build server + library to dist/
9
+ bun run dev # Watch mode (auto-restart on changes)
10
+ bun run test # Run tests
11
+ bun run typecheck # TypeScript validation
12
+ bun run check # Lint + format check
13
+ bun run lint:fix # Auto-fix lint issues
14
+ bun run format # Auto-fix formatting
15
+ bun run verify:ci # Full CI validation (typecheck + check + build + test)
16
+ ```
17
+
18
+ ## Architecture
19
+
20
+ MCP (Model Context Protocol) server built with `@modelcontextprotocol/sdk` and `@outfitter/mcp`.
21
+
22
+ ### Project Structure
23
+
24
+ - `src/server.ts` — Server entry point (stdio transport)
25
+ - `src/mcp.ts` — Tool and resource registration
26
+ - `src/tools/` — Tool definitions with Zod schemas and handler logic
27
+ - `src/index.ts` — Library re-exports for testing
28
+
29
+ ### Tool Definition
30
+
31
+ Tools are defined with `defineTool()` using Zod schemas for input validation and Result types for output:
32
+
33
+ ```typescript
34
+ import { Result, ValidationError } from "@outfitter/contracts";
35
+ import { defineTool } from "@outfitter/mcp";
36
+ import { z } from "zod";
37
+
38
+ const myTool = defineTool({
39
+ name: "my-tool",
40
+ description: "Does something useful",
41
+ inputSchema: z.object({ query: z.string().min(1) }),
42
+ annotations: { readOnlyHint: true },
43
+ handler: async (input, ctx): Promise<Result<MyOutput, ValidationError>> => {
44
+ if (!isValid(input.query)) {
45
+ return Result.err(ValidationError.create("query", "invalid format"));
46
+ }
47
+ return Result.ok({ data: await fetchData(input.query) });
48
+ },
49
+ });
50
+ ```
51
+
52
+ ### Resource Definition
53
+
54
+ Static resources use `defineResource()`:
55
+
56
+ ```typescript
57
+ import { Result } from "@outfitter/contracts";
58
+ import { defineResource } from "@outfitter/mcp";
59
+
60
+ const myResource = defineResource({
61
+ uri: "myapp:///config",
62
+ name: "Config",
63
+ handler: async (uri, _ctx) =>
64
+ Result.ok([{ uri, text: JSON.stringify(config) }]),
65
+ });
66
+ ```
67
+
68
+ ### Adding a Resource
69
+
70
+ Simple, self-contained resources (like `versionResource` in `src/mcp.ts`) can be defined inline — no separate file or re-export needed. For resources with non-trivial logic, extract to a dedicated file:
71
+
72
+ 1. Create resource file in `src/resources/<name>.ts` with `defineResource()`
73
+ 2. Import and register in `src/mcp.ts` via `server.registerResource()`
74
+ 3. Re-export from `src/index.ts`
75
+ 4. Add tests in `src/<name>.test.ts`
76
+
77
+ ### Adding a Tool
78
+
79
+ 1. Create tool file in `src/tools/<name>.ts` with `defineTool()`
80
+ 2. Import and register in `src/mcp.ts`
81
+ 3. Re-export from `src/index.ts`
82
+ 4. Add tests in `src/<name>.test.ts`
83
+
84
+ ## Development Principles
85
+
86
+ - **TDD-First** — Write the test before the code (Red / Green / Refactor)
87
+ - **Result Types** — Handlers return `Result<T, E>`, not exceptions
88
+ - **Bun-First** — Use Bun-native APIs before npm packages
89
+ - **Strict TypeScript** — No `any`, no `as` casts; narrow instead of assert
90
+
91
+ ## Testing
92
+
93
+ - Runner: Bun test runner
94
+ - Harness: `createMcpHarness()` from `@outfitter/testing` for protocol-level tests
95
+ - Files: `src/*.test.ts`
96
+ - Run: `bun test` or `bun run test`
97
+ - Test tool handlers directly by importing from `src/index.ts`
@@ -4,26 +4,28 @@
4
4
 
5
5
  MCP (Model Context Protocol) server for integration with AI assistants.
6
6
 
7
- ## Installation
8
-
9
- ```bash
10
- bun add {{packageName}}
11
- ```
12
-
13
- ## Usage with Claude Desktop
7
+ ## Claude Desktop Configuration
14
8
 
15
9
  Add to your Claude Desktop config:
16
10
 
11
+ - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
12
+ - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
13
+
17
14
  ```json
18
15
  {
19
16
  "mcpServers": {
20
- "{{binName}}": {
21
- "command": "{{binName}}"
17
+ "{{projectName}}": {
18
+ "command": "bun",
19
+ "args": ["run", "/absolute/path/to/{{projectName}}/src/server.ts"]
22
20
  }
23
21
  }
24
22
  }
25
23
  ```
26
24
 
25
+ Replace `/absolute/path/to/` with the actual path to your project directory.
26
+
27
+ > **Note:** On macOS, `bun` may not be on Claude Desktop's PATH. If the server fails to start, replace `"bun"` with the full path (e.g., `"/Users/you/.bun/bin/bun"` — run `which bun` to find it).
28
+
27
29
  ## Available Tools
28
30
 
29
31
  ### hello
@@ -31,6 +33,7 @@ Add to your Claude Desktop config:
31
33
  Say hello to someone.
32
34
 
33
35
  **Parameters:**
36
+
34
37
  - `name` (string, optional): Name to greet. Default: "World"
35
38
 
36
39
  ## Development