idiolect-mcp 0.1.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 (3) hide show
  1. package/README.md +32 -0
  2. package/package.json +17 -0
  3. package/server.mjs +88 -0
package/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # idiolect-mcp
2
+
3
+ MCP server that makes any MCP-compatible AI (Claude Desktop, Claude Code, …)
4
+ write in **your** voice, using your [Idiolect](https://idiolect.lol) Voice Card.
5
+
6
+ ## Setup
7
+
8
+ 1. Get your voice at **https://idiolect.lol** — note the slug in your result URL
9
+ (`idiolect.lol/v/<slug>`).
10
+ 2. Add to your MCP config:
11
+
12
+ ```json
13
+ {
14
+ "mcpServers": {
15
+ "idiolect": {
16
+ "command": "npx",
17
+ "args": ["-y", "idiolect-mcp"],
18
+ "env": { "IDIOLECT_SLUG": "your-slug" }
19
+ }
20
+ }
21
+ }
22
+ ```
23
+
24
+ ## Tool
25
+
26
+ - **`get_my_voice`** — returns your Voice Card. The model calls it before writing
27
+ on your behalf, then writes as you. Pass `slug` per-call or set `IDIOLECT_SLUG`.
28
+
29
+ Set `IDIOLECT_BASE` to point at a self-hosted instance (defaults to
30
+ `https://idiolect.lol`).
31
+
32
+ MIT licensed.
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "idiolect-mcp",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": { "idiolect-mcp": "server.mjs" },
6
+ "description": "MCP server that gives any MCP-compatible AI (Claude, etc.) your Idiolect voice — make AI write as you. https://idiolect.lol",
7
+ "keywords": ["mcp", "model-context-protocol", "claude", "ai", "writing", "voice", "idiolect"],
8
+ "homepage": "https://idiolect.lol",
9
+ "repository": { "type": "git", "url": "https://github.com/111mihir/idiolect.git", "directory": "mcp" },
10
+ "license": "MIT",
11
+ "files": ["server.mjs", "README.md"],
12
+ "engines": { "node": ">=18" },
13
+ "publishConfig": { "access": "public" },
14
+ "dependencies": {
15
+ "@modelcontextprotocol/sdk": "^1.0.4"
16
+ }
17
+ }
package/server.mjs ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ // Idiolect MCP server — gives any MCP-compatible AI (Claude Desktop, Claude
3
+ // Code, etc.) your personal voice. Configure with your Voice Card slug:
4
+ //
5
+ // {
6
+ // "mcpServers": {
7
+ // "idiolect": {
8
+ // "command": "node",
9
+ // "args": ["/path/to/idiolect/mcp/server.mjs"],
10
+ // "env": { "IDIOLECT_SLUG": "your-slug", "IDIOLECT_BASE": "https://idiolect.lol" }
11
+ // }
12
+ // }
13
+ // }
14
+
15
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
16
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
17
+ import {
18
+ CallToolRequestSchema,
19
+ ListToolsRequestSchema,
20
+ } from "@modelcontextprotocol/sdk/types.js";
21
+
22
+ const BASE = process.env.IDIOLECT_BASE || "https://idiolect.lol";
23
+ const DEFAULT_SLUG = process.env.IDIOLECT_SLUG || "";
24
+
25
+ async function fetchVoice(slug) {
26
+ const res = await fetch(`${BASE}/api/voice/${encodeURIComponent(slug)}`);
27
+ if (!res.ok) throw new Error(`Idiolect: voice "${slug}" not found (${res.status})`);
28
+ return res.json();
29
+ }
30
+
31
+ const server = new Server(
32
+ { name: "idiolect", version: "0.1.0" },
33
+ { capabilities: { tools: {} } },
34
+ );
35
+
36
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
37
+ tools: [
38
+ {
39
+ name: "get_my_voice",
40
+ description:
41
+ "Load the user's Idiolect Voice Card. Call this BEFORE writing anything on the user's behalf (emails, posts, messages, docs) and then write strictly in the returned voice. Returns a style guide describing how the user actually writes.",
42
+ inputSchema: {
43
+ type: "object",
44
+ properties: {
45
+ slug: {
46
+ type: "string",
47
+ description:
48
+ "Idiolect voice slug. Optional if IDIOLECT_SLUG is set in the server env.",
49
+ },
50
+ },
51
+ },
52
+ },
53
+ ],
54
+ }));
55
+
56
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
57
+ if (req.params.name !== "get_my_voice") {
58
+ throw new Error(`Unknown tool: ${req.params.name}`);
59
+ }
60
+ const slug = req.params.arguments?.slug || DEFAULT_SLUG;
61
+ if (!slug) {
62
+ return {
63
+ content: [
64
+ {
65
+ type: "text",
66
+ text: "No Idiolect slug provided. Pass `slug` or set IDIOLECT_SLUG. Get yours at https://idiolect.lol",
67
+ },
68
+ ],
69
+ isError: true,
70
+ };
71
+ }
72
+ try {
73
+ const v = await fetchVoice(slug);
74
+ return {
75
+ content: [
76
+ {
77
+ type: "text",
78
+ text: `${v.voiceCard}\n\n---\n(Idiolect voice #${slug} · genericness ${v.genericnessScore}/100. Write everything as this person from now on.)`,
79
+ },
80
+ ],
81
+ };
82
+ } catch (e) {
83
+ return { content: [{ type: "text", text: String(e) }], isError: true };
84
+ }
85
+ });
86
+
87
+ const transport = new StdioServerTransport();
88
+ await server.connect(transport);