idiolect-mcp 0.5.0 → 0.5.1
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.
- package/package.json +3 -2
- package/public-contract.js +85 -0
- package/server.mjs +19 -1
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "idiolect-mcp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"mcpName": "app.idiolect/idiolect-ai",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"idiolect-mcp": "server.mjs"
|
|
8
8
|
},
|
|
9
|
-
"description": "MCP server that gives any MCP-compatible AI (Claude, etc.) your Idiolect AI voice
|
|
9
|
+
"description": "MCP server that gives any MCP-compatible AI (Claude, etc.) your Idiolect AI voice \u2014 make AI write as you. https://idiolect.app",
|
|
10
10
|
"keywords": [
|
|
11
11
|
"mcp",
|
|
12
12
|
"model-context-protocol",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"files": [
|
|
26
26
|
"server.mjs",
|
|
27
|
+
"public-contract.js",
|
|
27
28
|
"progressive-catalog.json",
|
|
28
29
|
"README.md"
|
|
29
30
|
],
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Generated from lib/mcp/public-contract.js by `npm run mcp:generate-public-artifacts`. Do not edit.
|
|
2
|
+
export const PUBLIC_MCP_TOOL_NAMES = Object.freeze([
|
|
3
|
+
"get_my_voice",
|
|
4
|
+
"create_my_voice",
|
|
5
|
+
"draft_in_voice",
|
|
6
|
+
"rewrite_in_voice",
|
|
7
|
+
"score_voice",
|
|
8
|
+
"record_voice_feedback",
|
|
9
|
+
"learn_writing_style",
|
|
10
|
+
"list_writing_profiles",
|
|
11
|
+
"list_writing_profile_samples",
|
|
12
|
+
"create_writing_profile",
|
|
13
|
+
"add_samples_to_writing_profile",
|
|
14
|
+
"replace_samples_in_writing_profile",
|
|
15
|
+
"remove_sample_from_writing_profile",
|
|
16
|
+
"set_current_writing_profile",
|
|
17
|
+
"delete_writing_profile",
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
// Decision for the 2026-08-10 high-arrival review: keep measurement available,
|
|
21
|
+
// but tell hosts to invoke it only when the user explicitly asks for a check.
|
|
22
|
+
// Unmeasured results must continue to say why and expose scorer provenance.
|
|
23
|
+
export const SCORE_VOICE_ADVERTISING_DECISION = Object.freeze({
|
|
24
|
+
advertised: true,
|
|
25
|
+
invocation: "explicit_request_only",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const PUBLIC_STATES = new Set([
|
|
29
|
+
"ready",
|
|
30
|
+
"missing",
|
|
31
|
+
"thin",
|
|
32
|
+
"stale",
|
|
33
|
+
"complete",
|
|
34
|
+
"failed",
|
|
35
|
+
]);
|
|
36
|
+
const NEXT_ACTIONS = new Set([
|
|
37
|
+
"collect_evidence",
|
|
38
|
+
"reload_voice",
|
|
39
|
+
"continue_writing",
|
|
40
|
+
"ask_feedback",
|
|
41
|
+
"retry",
|
|
42
|
+
"done",
|
|
43
|
+
]);
|
|
44
|
+
const NEXT_TOOLS = new Set([
|
|
45
|
+
"create_my_voice",
|
|
46
|
+
"get_my_voice",
|
|
47
|
+
"record_voice_feedback",
|
|
48
|
+
null,
|
|
49
|
+
]);
|
|
50
|
+
const SERVER_ONLY_KEYS = new Set([
|
|
51
|
+
"workflowId",
|
|
52
|
+
"baseVersion",
|
|
53
|
+
"idempotencyKey",
|
|
54
|
+
"onboardingIdempotencyKey",
|
|
55
|
+
"leaseToken",
|
|
56
|
+
"fencingToken",
|
|
57
|
+
"attemptToken",
|
|
58
|
+
"buildBindingId",
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
function stripServerOnly(value) {
|
|
62
|
+
if (Array.isArray(value)) return value.map(stripServerOnly);
|
|
63
|
+
if (!value || typeof value !== "object") return value;
|
|
64
|
+
return Object.fromEntries(
|
|
65
|
+
Object.entries(value)
|
|
66
|
+
.filter(([key]) => !SERVER_ONLY_KEYS.has(key))
|
|
67
|
+
.map(([key, nested]) => [key, stripServerOnly(nested)]),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build the only model-visible state/continuation envelope. Details are copied
|
|
73
|
+
* through a denylist so internal coordination receipts cannot leak by spread.
|
|
74
|
+
*/
|
|
75
|
+
export function publicMcpState(state, message, next, details = {}) {
|
|
76
|
+
if (!PUBLIC_STATES.has(state)) throw new TypeError(`Unknown public MCP state: ${state}`);
|
|
77
|
+
if (!next || !NEXT_ACTIONS.has(next.action) || !NEXT_TOOLS.has(next.tool)) {
|
|
78
|
+
throw new TypeError("Invalid public MCP next action");
|
|
79
|
+
}
|
|
80
|
+
const safeDetails = stripServerOnly(details);
|
|
81
|
+
delete safeDetails.state;
|
|
82
|
+
delete safeDetails.message;
|
|
83
|
+
delete safeDetails.next;
|
|
84
|
+
return { state, message, ...safeDetails, next: { action: next.action, tool: next.tool } };
|
|
85
|
+
}
|
package/server.mjs
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
35
35
|
import {
|
|
36
36
|
publicMcpState,
|
|
37
|
-
} from "
|
|
37
|
+
} from "./public-contract.js";
|
|
38
38
|
|
|
39
39
|
const progressiveCatalog = JSON.parse(
|
|
40
40
|
readFileSync(new URL("./progressive-catalog.json", import.meta.url), "utf8"),
|
|
@@ -489,6 +489,18 @@ const BRIEF_AUTHOR_SCHEMA = {
|
|
|
489
489
|
description:
|
|
490
490
|
"Who wrote the brief. `user` only when the person wrote it themselves; `host` when you (the assistant) drafted it; `other` for a third party's text. Leave it out if unsure.",
|
|
491
491
|
};
|
|
492
|
+
const CALIBRATION_SCHEMA = {
|
|
493
|
+
type: "object",
|
|
494
|
+
properties: {
|
|
495
|
+
direction: {
|
|
496
|
+
type: "string",
|
|
497
|
+
enum: ["direct", "balanced", "gentle"],
|
|
498
|
+
description: "The user's answer to the single task-local calibration question.",
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
required: ["direction"],
|
|
502
|
+
additionalProperties: false,
|
|
503
|
+
};
|
|
492
504
|
|
|
493
505
|
/** Validates `sourceAuthor`/`briefAuthor` and defaults an absent one to `"unknown"` on the
|
|
494
506
|
* returned copy of `args`. Returns a tool error, never throws. */
|
|
@@ -1052,6 +1064,7 @@ const accountToolDefinitions = [
|
|
|
1052
1064
|
changeScope: CHANGE_SCOPE_SCHEMA,
|
|
1053
1065
|
effects: EFFECTS_SCHEMA,
|
|
1054
1066
|
sourceAuthor: SOURCE_AUTHOR_SCHEMA,
|
|
1067
|
+
calibration: CALIBRATION_SCHEMA,
|
|
1055
1068
|
profileId: { type: "string", format: "uuid", description: "Use this owned Writing Profile for this piece only. Select an exact profileId; this does not change the account default." },
|
|
1056
1069
|
},
|
|
1057
1070
|
required: ["text"],
|
|
@@ -1090,6 +1103,7 @@ const accountToolDefinitions = [
|
|
|
1090
1103
|
},
|
|
1091
1104
|
effects: EFFECTS_SCHEMA,
|
|
1092
1105
|
briefAuthor: BRIEF_AUTHOR_SCHEMA,
|
|
1106
|
+
calibration: CALIBRATION_SCHEMA,
|
|
1093
1107
|
profileId: { type: "string", format: "uuid", description: "Use this owned Writing Profile for this piece only. Select an exact profileId; this does not change the account default." },
|
|
1094
1108
|
},
|
|
1095
1109
|
required: ["brief"],
|
|
@@ -1618,6 +1632,7 @@ export async function handleToolRequest(req) {
|
|
|
1618
1632
|
const changeScope = args.changeScope === "polish" ? "light_edit" : args.changeScope;
|
|
1619
1633
|
const effects = args.effects;
|
|
1620
1634
|
const sourceAuthor = args.sourceAuthor;
|
|
1635
|
+
const calibration = args.calibration;
|
|
1621
1636
|
if (!text) {
|
|
1622
1637
|
return { content: [{ type: "text", text: "rewrite_in_voice: provide `text` to rewrite." }], isError: true };
|
|
1623
1638
|
}
|
|
@@ -1643,6 +1658,7 @@ export async function handleToolRequest(req) {
|
|
|
1643
1658
|
...(changeScope !== undefined ? { changeScope } : {}),
|
|
1644
1659
|
...(effects !== undefined ? { effects } : {}),
|
|
1645
1660
|
...(sourceAuthor !== undefined ? { sourceAuthor } : {}),
|
|
1661
|
+
...(calibration !== undefined ? { calibration } : {}),
|
|
1646
1662
|
},
|
|
1647
1663
|
toolName: "rewrite_in_voice",
|
|
1648
1664
|
});
|
|
@@ -1678,6 +1694,7 @@ export async function handleToolRequest(req) {
|
|
|
1678
1694
|
const changeScope = args.changeScope === "polish" ? "light_edit" : args.changeScope;
|
|
1679
1695
|
const effects = args.effects;
|
|
1680
1696
|
const briefAuthor = args.briefAuthor;
|
|
1697
|
+
const calibration = args.calibration;
|
|
1681
1698
|
if (!brief) {
|
|
1682
1699
|
return { content: [{ type: "text", text: "draft_in_voice: provide `brief` to draft from." }], isError: true };
|
|
1683
1700
|
}
|
|
@@ -1703,6 +1720,7 @@ export async function handleToolRequest(req) {
|
|
|
1703
1720
|
...(changeScope !== undefined ? { changeScope } : {}),
|
|
1704
1721
|
...(effects !== undefined ? { effects } : {}),
|
|
1705
1722
|
...(briefAuthor !== undefined ? { briefAuthor } : {}),
|
|
1723
|
+
...(calibration !== undefined ? { calibration } : {}),
|
|
1706
1724
|
},
|
|
1707
1725
|
toolName: "draft_in_voice",
|
|
1708
1726
|
});
|