@markmnl/fmsg-mcp 1.5.1 → 1.5.2
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/CHANGELOG.md +6 -0
- package/dist/build-info.json +3 -3
- package/dist/tools/download.js +5 -2
- package/dist/tools/read.js +4 -1
- package/dist/tools/send.js +8 -5
- package/package.json +1 -1
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- Tool annotations follow OpenAI's plugin guidelines ("false only for additive writes without
|
|
6
|
+
destructive or irreversible effects"), after a directory review flagged them: `react`, `indicate`
|
|
7
|
+
and `mark_read` are `destructiveHint: true` (a reaction or status reaches the other participants at
|
|
8
|
+
once and supersedes the previous one; marking read can't be undone here), so a host may ask before
|
|
9
|
+
each. `get_attachment_download_url` is no longer `readOnlyHint` (its presigned link is created on the
|
|
10
|
+
server); it still needs only `fmsg:read`.
|
|
5
11
|
- `send_message`, `reply` and `create_draft` take `files`: files the user shared in the chat, given by
|
|
6
12
|
reference (ChatGPT's `openai/fileParams`, declared in each tool's `_meta`). The server downloads each
|
|
7
13
|
one, from public HTTPS addresses only, hashes it, attaches the exact bytes and reports its sha256 in
|
package/dist/build-info.json
CHANGED
package/dist/tools/download.js
CHANGED
|
@@ -6,7 +6,7 @@ import { toolError } from "../errors.js";
|
|
|
6
6
|
import { localFileName, shellQuote } from "../links.js";
|
|
7
7
|
import { attachmentType, isoTime, messageData } from "../render.js";
|
|
8
8
|
import { FILENAME } from "./attachments.js";
|
|
9
|
-
import { SENDS, attachmentMissingFrom, idSchema, openEnum, outputObject,
|
|
9
|
+
import { SENDS, attachmentMissingFrom, idSchema, openEnum, outputObject, UNTRUSTED, untrustedNotice, withCaller } from "./common.js";
|
|
10
10
|
const FALLBACK = "If you cannot fetch URLs with this connection's authorization, use download_attachment instead.";
|
|
11
11
|
const PRESIGNED_FALLBACK = "If you cannot fetch URLs with this connection's authorization, pass presigned: true for a single-use link that needs none.";
|
|
12
12
|
const presignedOutput = outputObject({
|
|
@@ -46,7 +46,10 @@ export const registerDownloadTool = (server, deps) => {
|
|
|
46
46
|
presigned: presignedOutput.partial().optional().describe("present when presigned was true"),
|
|
47
47
|
...untrustedNotice,
|
|
48
48
|
}),
|
|
49
|
-
|
|
49
|
+
// Not read-only: with presigned it creates a short-lived single-use
|
|
50
|
+
// download link. Not destructive: it changes no messages. Closed-world:
|
|
51
|
+
// only the caller's own attachments. Reading needs only fmsg:read.
|
|
52
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
50
53
|
}, async ({ id, filename, presigned }, ctx) => withCaller(deps, ctx, async (caller, signal) => {
|
|
51
54
|
const mid = normalizeMessageId(id);
|
|
52
55
|
attachmentFilename(filename);
|
package/dist/tools/read.js
CHANGED
|
@@ -166,7 +166,10 @@ export const registerReadTools = (server, deps) => {
|
|
|
166
166
|
marked: z.array(outputObject({ id: z.string(), time_read: z.string().nullable() })),
|
|
167
167
|
failed: z.array(outputObject({ id: z.string(), error: z.string() })),
|
|
168
168
|
}),
|
|
169
|
-
|
|
169
|
+
// Destructive (OpenAI's plugin guidelines): marking read changes the
|
|
170
|
+
// messages' read state, which this server cannot undo. Closed-world:
|
|
171
|
+
// only the caller's own mailbox.
|
|
172
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
170
173
|
}, async ({ ids }, ctx) => withCaller(deps, ctx, async (caller, signal) => {
|
|
171
174
|
deps.indicators.handled(caller, ids);
|
|
172
175
|
const marked = [];
|
package/dist/tools/send.js
CHANGED
|
@@ -254,10 +254,11 @@ export const registerSendTools = (server, deps) => {
|
|
|
254
254
|
emoji: z.string().max(32).nullable().describe("a single emoji; null or empty clears your reaction"),
|
|
255
255
|
}),
|
|
256
256
|
outputSchema: outputObject({ id: z.string(), reaction_id: z.string().nullable(), time: z.string().nullable(), cleared: z.boolean() }),
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
|
|
257
|
+
// Destructive (OpenAI's plugin guidelines): a reaction is a send the
|
|
258
|
+
// other participants receive at once and cannot be recalled, and it
|
|
259
|
+
// supersedes the sender's previous reaction. Earlier reaction messages
|
|
260
|
+
// stay; setting the same emoji again is a no-op.
|
|
261
|
+
annotations: { ...SENDS, idempotentHint: true },
|
|
261
262
|
}, async ({ id, emoji }, ctx) => withCaller(deps, ctx, async (caller, signal) => {
|
|
262
263
|
const value = emoji && emoji.trim() ? emoji.trim() : null;
|
|
263
264
|
const result = await caller.client.react(id, value, signal);
|
|
@@ -281,7 +282,9 @@ export const registerSendTools = (server, deps) => {
|
|
|
281
282
|
ttl: z.number().describe("seconds; 0 when cleared"),
|
|
282
283
|
cleared: z.boolean(),
|
|
283
284
|
}),
|
|
284
|
-
|
|
285
|
+
// Destructive (OpenAI's plugin guidelines): the status is shown to the
|
|
286
|
+
// other participants at once and replaces the caller's previous one.
|
|
287
|
+
annotations: { ...SENDS, idempotentHint: true },
|
|
285
288
|
}, async ({ id, emoji, ttl }, ctx) => withCaller(deps, ctx, async (caller, signal) => {
|
|
286
289
|
const value = emoji.trim();
|
|
287
290
|
// The thread root lets a reply anywhere in the thread clear it; a failed lookup only means it is not known.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markmnl/fmsg-mcp",
|
|
3
3
|
"mcpName": "io.github.markmnl/fmsg-mcp",
|
|
4
|
-
"version": "1.5.
|
|
4
|
+
"version": "1.5.2",
|
|
5
5
|
"description": "MCP server for fmsg: send and receive federated messages from any AI agent via a deployed fmsg Web API",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
package/server.json
CHANGED
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"url": "https://github.com/markmnl/fmsg-mcp",
|
|
9
9
|
"source": "github"
|
|
10
10
|
},
|
|
11
|
-
"version": "1.5.
|
|
11
|
+
"version": "1.5.2",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
16
16
|
"identifier": "@markmnl/fmsg-mcp",
|
|
17
|
-
"version": "1.5.
|
|
17
|
+
"version": "1.5.2",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
20
20
|
},
|