@markmnl/fmsg-mcp 0.2.4 → 0.2.5
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/README.md +1 -1
- package/dist/address.d.ts +13 -1
- package/dist/address.js +18 -3
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -2
- package/dist/index.js +2 -1
- package/dist/instructions.d.ts +1 -6
- package/dist/instructions.js +13 -3
- package/dist/tools/common.d.ts +3 -0
- package/dist/tools/common.js +4 -0
- package/dist/tools/identity.js +20 -13
- package/dist/tools/send.js +4 -4
- package/dist/tools/wait.js +2 -2
- package/docs/http-deployment.md +5 -0
- 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
|
+
- Add `FMSG_DEFAULT_DOMAIN=caller` (case-insensitive): short names resolve on the domain of the
|
|
6
|
+
address the server acts as for each request, so a deployment serving callers on several domains
|
|
7
|
+
resolves `bob` to `@bob@example.org` for `@mark@example.org` and `@bob@example.net` for a caller
|
|
8
|
+
on `example.net`. `whoami`'s `default_domain` and the server instructions show the caller's
|
|
9
|
+
domain. Over stdio, `resolve_address` first looks up the configured key's address. Directory
|
|
10
|
+
entries still take precedence; a fixed or unset default domain is unchanged.
|
|
5
11
|
- Add HTTP `FMSG_MCP_AUTH_MODE=oauth+api-key`, serving OAuth and API-key callers on one endpoint.
|
|
6
12
|
`Bearer fmsgk_...` requests use API-key authentication; all others, including unauthenticated
|
|
7
13
|
requests, use OAuth with its discovery challenge and scope checks. Providers and caches stay
|
package/README.md
CHANGED
|
@@ -159,7 +159,7 @@ attach resources; prompts `chat` and `reply` script the wait → reply loop and
|
|
|
159
159
|
| `FMSG_MCP_AUTH_MODE` | `api-key` | HTTP authentication: `api-key`, `oauth`, or `oauth+api-key` to accept both on one endpoint; see [OAuth settings](docs/oauth.md#operator-configuration) and [combined mode](docs/oauth.md#combined-oauth-and-api-key-mode) |
|
|
160
160
|
| `FMSG_MCP_PUBLIC_URL` | OAuth resource URL, otherwise unset | Public MCP endpoint, including `/mcp`; enables the HTTP download-link tool. HTTPS required except loopback; when OAuth is enabled must equal `FMSG_MCP_OAUTH_RESOURCE_URL` |
|
|
161
161
|
| `FMSG_ALLOW_INSECURE_HTTP` | disabled | Set to `1` only to permit cleartext API access on a trusted development/private network; loopback HTTP is allowed by default |
|
|
162
|
-
| `FMSG_DEFAULT_DOMAIN` | — | Lets short names resolve: `bob` → `@bob@<domain
|
|
162
|
+
| `FMSG_DEFAULT_DOMAIN` | — | Lets short names resolve: `bob` → `@bob@<domain>`. `caller` resolves them on the domain of the address the server acts as for each request, so `@mark@example.org` gets `@bob@example.org`; directory entries still take precedence |
|
|
163
163
|
| `FMSG_DIRECTORY` | — | JSON file mapping short names to full addresses |
|
|
164
164
|
| `FMSG_MCP_DOWNLOAD_DIR` | — | Enable `save_attachment` in stdio; folder for new files named from message ID and filename |
|
|
165
165
|
| `FMSG_MCP_WAIT_MAX_SECONDS` | `230` | Cap on one `wait_for_message` call |
|
package/dist/address.d.ts
CHANGED
|
@@ -8,10 +8,21 @@ export declare function normalizeFmsgAddress(value: string): string | undefined;
|
|
|
8
8
|
/** Case-insensitive address equality. */
|
|
9
9
|
export declare function sameAddress(a: string, b: string): boolean;
|
|
10
10
|
export declare function isFmsgAddress(value: string): boolean;
|
|
11
|
+
/** Reserved FMSG_DEFAULT_DOMAIN value: short names resolve on the caller's own domain. */
|
|
12
|
+
export declare const CALLER_DOMAIN = "caller";
|
|
13
|
+
/**
|
|
14
|
+
* The domain short names resolve to: the configured default domain, or with
|
|
15
|
+
* `caller` the domain of the address the server acts as. Undefined when neither
|
|
16
|
+
* is known (no default domain, or `caller` before the caller address is known).
|
|
17
|
+
*/
|
|
18
|
+
export declare function effectiveDefaultDomain(defaultDomain: string | undefined, callerAddress?: string): string | undefined;
|
|
11
19
|
export type Resolution = "literal" | "directory" | "default_domain";
|
|
12
20
|
export type AddressResolver = {
|
|
21
|
+
/** A domain, or CALLER_DOMAIN to use the domain of `callerAddress`. */
|
|
13
22
|
defaultDomain?: string;
|
|
14
23
|
directory?: Record<string, string>;
|
|
24
|
+
/** The address the server acts as, when known. */
|
|
25
|
+
callerAddress?: string;
|
|
15
26
|
};
|
|
16
27
|
export type ResolvedAddress = {
|
|
17
28
|
address: string;
|
|
@@ -19,7 +30,8 @@ export type ResolvedAddress = {
|
|
|
19
30
|
};
|
|
20
31
|
/**
|
|
21
32
|
* Resolve a full address or short name: literal `@user@domain` first, then a
|
|
22
|
-
* configured directory entry, then `@name@<default domain
|
|
33
|
+
* configured directory entry, then `@name@<default domain>` (the caller's own
|
|
34
|
+
* domain when the default domain is `caller`).
|
|
23
35
|
*/
|
|
24
36
|
export declare function resolveAddress(name: string, resolver?: AddressResolver): ResolvedAddress;
|
|
25
37
|
export declare function resolveAddresses(names: string[], resolver?: AddressResolver): string[];
|
package/dist/address.js
CHANGED
|
@@ -19,9 +19,23 @@ export function sameAddress(a, b) {
|
|
|
19
19
|
export function isFmsgAddress(value) {
|
|
20
20
|
return normalizeFmsgAddress(value) !== undefined;
|
|
21
21
|
}
|
|
22
|
+
/** Reserved FMSG_DEFAULT_DOMAIN value: short names resolve on the caller's own domain. */
|
|
23
|
+
export const CALLER_DOMAIN = "caller";
|
|
24
|
+
/**
|
|
25
|
+
* The domain short names resolve to: the configured default domain, or with
|
|
26
|
+
* `caller` the domain of the address the server acts as. Undefined when neither
|
|
27
|
+
* is known (no default domain, or `caller` before the caller address is known).
|
|
28
|
+
*/
|
|
29
|
+
export function effectiveDefaultDomain(defaultDomain, callerAddress) {
|
|
30
|
+
if (defaultDomain !== CALLER_DOMAIN)
|
|
31
|
+
return defaultDomain;
|
|
32
|
+
const match = callerAddress ? ADDRESS.exec(callerAddress.trim()) : null;
|
|
33
|
+
return match ? match[2].toLowerCase() : undefined;
|
|
34
|
+
}
|
|
22
35
|
/**
|
|
23
36
|
* Resolve a full address or short name: literal `@user@domain` first, then a
|
|
24
|
-
* configured directory entry, then `@name@<default domain
|
|
37
|
+
* configured directory entry, then `@name@<default domain>` (the caller's own
|
|
38
|
+
* domain when the default domain is `caller`).
|
|
25
39
|
*/
|
|
26
40
|
export function resolveAddress(name, resolver = {}) {
|
|
27
41
|
const trimmed = name.trim();
|
|
@@ -41,8 +55,9 @@ export function resolveAddress(name, resolver = {}) {
|
|
|
41
55
|
return { address, resolution: "directory" };
|
|
42
56
|
}
|
|
43
57
|
}
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
const domain = effectiveDefaultDomain(resolver.defaultDomain, resolver.callerAddress);
|
|
59
|
+
if (domain) {
|
|
60
|
+
const address = normalizeFmsgAddress(`@${trimmed}@${domain}`);
|
|
46
61
|
if (address)
|
|
47
62
|
return { address, resolution: "default_domain" };
|
|
48
63
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export type Config = {
|
|
|
25
25
|
allowInsecureHttp?: boolean;
|
|
26
26
|
/** Only set in stdio mode. */
|
|
27
27
|
apiKey?: string;
|
|
28
|
+
/** Domain for short names, or CALLER_DOMAIN for each caller's own domain. */
|
|
28
29
|
defaultDomain?: string;
|
|
29
30
|
directory?: Record<string, string>;
|
|
30
31
|
/** Trusted local destination; enables save_attachment over stdio only. */
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import { normalizeFmsgAddress } from "./address.js";
|
|
2
|
+
import { CALLER_DOMAIN, normalizeFmsgAddress } from "./address.js";
|
|
3
3
|
import { normalizeApiUrl, normalizeOrigin } from "./client/url.js";
|
|
4
4
|
import { loadOAuthConfig, oauthUrl } from "./oauth/config.js";
|
|
5
5
|
export const DEFAULT_HTTP_PORT = 8765;
|
|
@@ -74,7 +74,8 @@ export function loadConfig(env, transport, overrides = {}, options = {}) {
|
|
|
74
74
|
if (transport === "http" && apiKey) {
|
|
75
75
|
throw new Error("FMSG_API_KEY must not be set in HTTP mode: each client supplies its own bearer credential");
|
|
76
76
|
}
|
|
77
|
-
const
|
|
77
|
+
const rawDefaultDomain = env.FMSG_DEFAULT_DOMAIN?.trim().replace(/^@/u, "") || undefined;
|
|
78
|
+
const defaultDomain = rawDefaultDomain?.toLowerCase() === CALLER_DOMAIN ? CALLER_DOMAIN : rawDefaultDomain;
|
|
78
79
|
const directoryPath = env.FMSG_DIRECTORY?.trim();
|
|
79
80
|
const port = overrides.port ?? intEnv(env, "FMSG_MCP_PORT", DEFAULT_HTTP_PORT, 0);
|
|
80
81
|
if (!Number.isInteger(port) || port < 0 || port > 65535)
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,8 @@ Environment:
|
|
|
29
29
|
FMSG_MCP_OAUTH_* OAuth resource/issuer URLs, client ID/secret and exchange
|
|
30
30
|
audience; see docs/oauth.md for required settings
|
|
31
31
|
FMSG_ALLOW_INSECURE_HTTP 1 to allow a trusted private HTTP API outside loopback
|
|
32
|
-
FMSG_DEFAULT_DOMAIN lets short names resolve: bob -> @bob@<domain
|
|
32
|
+
FMSG_DEFAULT_DOMAIN lets short names resolve: bob -> @bob@<domain>; caller
|
|
33
|
+
uses the domain of each caller's own address
|
|
33
34
|
FMSG_DIRECTORY JSON file mapping short names to @user@domain
|
|
34
35
|
FMSG_MCP_DOWNLOAD_DIR enables save_attachment to this local folder (stdio)
|
|
35
36
|
FMSG_MCP_WAIT_MAX_SECONDS cap on one wait_for_message call (default 230)
|
package/dist/instructions.d.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server instructions: returned in the MCP `initialize` result and folded into
|
|
3
|
-
* the model's system prompt by hosts. Three jobs only: precedence over other
|
|
4
|
-
* fmsg access paths, the irreversible-send rule, and the usage facts a model
|
|
5
|
-
* otherwise gets wrong. Per-tool detail lives in the tool descriptions.
|
|
6
|
-
*/
|
|
7
1
|
export type InstructionsContext = {
|
|
8
2
|
/** The address this server acts as, when already known (HTTP callers; stdio after a token exchange). */
|
|
9
3
|
address?: string;
|
|
4
|
+
/** FMSG_DEFAULT_DOMAIN: a domain, or CALLER_DOMAIN for the caller's own domain. */
|
|
10
5
|
defaultDomain?: string;
|
|
11
6
|
};
|
|
12
7
|
export declare function buildInstructions(ctx?: InstructionsContext): string;
|
package/dist/instructions.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server instructions: returned in the MCP `initialize` result and folded into
|
|
3
|
+
* the model's system prompt by hosts. Three jobs only: precedence over other
|
|
4
|
+
* fmsg access paths, the irreversible-send rule, and the usage facts a model
|
|
5
|
+
* otherwise gets wrong. Per-tool detail lives in the tool descriptions.
|
|
6
|
+
*/
|
|
7
|
+
import { CALLER_DOMAIN, effectiveDefaultDomain } from "./address.js";
|
|
1
8
|
export function buildInstructions(ctx = {}) {
|
|
2
9
|
const identity = ctx.address
|
|
3
10
|
? `you are acting as ${ctx.address}`
|
|
4
11
|
: "call whoami to see which";
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
12
|
+
const domain = effectiveDefaultDomain(ctx.defaultDomain, ctx.address);
|
|
13
|
+
const shortNames = domain
|
|
14
|
+
? `; short names resolve to @name@${domain}`
|
|
15
|
+
: ctx.defaultDomain === CALLER_DOMAIN
|
|
16
|
+
? "; short names resolve to @name@<your domain>, the domain of the address you act as"
|
|
17
|
+
: "";
|
|
8
18
|
return [
|
|
9
19
|
`This server sends and receives fmsg messages as one fmsg address: ${identity}. ` +
|
|
10
20
|
"Use its tools for everything fmsg: inbox, threads, attachments, sending, replying, reactions, " +
|
package/dist/tools/common.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CallToolResult, McpServer, ServerContext, ToolAnnotations } from "@modelcontextprotocol/server";
|
|
2
2
|
import * as z from "zod/v4";
|
|
3
|
+
import type { AddressResolver } from "../address.js";
|
|
3
4
|
import type { FmsgMessage } from "../client/types.js";
|
|
4
5
|
import type { Config } from "../config.js";
|
|
5
6
|
import { type Caller, type CallerProvider } from "../context.js";
|
|
@@ -57,6 +58,8 @@ export type MessageItem = z.infer<typeof messageItem>;
|
|
|
57
58
|
export declare function toItem(m: FmsgMessage, self: string): MessageItem;
|
|
58
59
|
export declare function deliveryOf(m: FmsgMessage): z.infer<typeof deliveryItem>[];
|
|
59
60
|
export declare function ok(text: string, structured: Record<string, unknown>): CallToolResult;
|
|
61
|
+
/** Short-name resolution for this caller: the configured directory and default domain. */
|
|
62
|
+
export declare function resolverFor(deps: ToolDeps, caller: Caller): AddressResolver;
|
|
60
63
|
/** Resolve the caller and run a tool body, turning any failure into an `isError` result. */
|
|
61
64
|
export declare function withCaller(deps: ToolDeps, ctx: ServerContext, body: (caller: Caller, signal: AbortSignal) => Promise<CallToolResult>): Promise<CallToolResult>;
|
|
62
65
|
export type Register = (server: McpServer, deps: ToolDeps) => void;
|
package/dist/tools/common.js
CHANGED
|
@@ -72,6 +72,10 @@ export function deliveryOf(m) {
|
|
|
72
72
|
export function ok(text, structured) {
|
|
73
73
|
return { content: [{ type: "text", text }], structuredContent: structured };
|
|
74
74
|
}
|
|
75
|
+
/** Short-name resolution for this caller: the configured directory and default domain. */
|
|
76
|
+
export function resolverFor(deps, caller) {
|
|
77
|
+
return { ...deps.config, callerAddress: caller.address };
|
|
78
|
+
}
|
|
75
79
|
/** Resolve the caller and run a tool body, turning any failure into an `isError` result. */
|
|
76
80
|
export async function withCaller(deps, ctx, body) {
|
|
77
81
|
let caller;
|
package/dist/tools/identity.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as z from "zod/v4";
|
|
2
|
-
import { resolveAddress } from "../address.js";
|
|
2
|
+
import { CALLER_DOMAIN, effectiveDefaultDomain, resolveAddress } from "../address.js";
|
|
3
3
|
import { isoTime } from "../render.js";
|
|
4
|
-
import { READ_ONLY, ok, withCaller } from "./common.js";
|
|
4
|
+
import { READ_ONLY, ok, resolverFor, withCaller } from "./common.js";
|
|
5
5
|
import { toolError } from "../errors.js";
|
|
6
6
|
export const registerIdentityTools = (server, deps) => {
|
|
7
7
|
server.registerTool("whoami", {
|
|
@@ -21,12 +21,13 @@ export const registerIdentityTools = (server, deps) => {
|
|
|
21
21
|
annotations: { ...READ_ONLY, openWorldHint: false },
|
|
22
22
|
}, async (ctx) => withCaller(deps, ctx, async (caller) => {
|
|
23
23
|
const expires = isoTime((await caller.tokenExpiresAt()) / 1000);
|
|
24
|
+
const defaultDomain = effectiveDefaultDomain(deps.config.defaultDomain, caller.address);
|
|
24
25
|
const structured = {
|
|
25
26
|
address: caller.address,
|
|
26
27
|
api_url: deps.config.apiPublicUrl ?? null,
|
|
27
28
|
token_expires_at: expires,
|
|
28
29
|
transport: deps.config.transport,
|
|
29
|
-
default_domain:
|
|
30
|
+
default_domain: defaultDomain ?? null,
|
|
30
31
|
directory_names: Object.keys(deps.config.directory ?? {}),
|
|
31
32
|
};
|
|
32
33
|
const lines = [
|
|
@@ -35,8 +36,8 @@ export const registerIdentityTools = (server, deps) => {
|
|
|
35
36
|
: `You are **${caller.address}** (${deps.config.transport}).`,
|
|
36
37
|
`Access token expires ${expires ?? "unknown"} and is renewed automatically.`,
|
|
37
38
|
];
|
|
38
|
-
if (
|
|
39
|
-
lines.push(`Short names resolve to @name@${
|
|
39
|
+
if (defaultDomain)
|
|
40
|
+
lines.push(`Short names resolve to @name@${defaultDomain}.`);
|
|
40
41
|
if (structured.directory_names.length)
|
|
41
42
|
lines.push(`Directory names: ${structured.directory_names.join(", ")}.`);
|
|
42
43
|
return ok(lines.join("\n"), structured);
|
|
@@ -49,13 +50,19 @@ export const registerIdentityTools = (server, deps) => {
|
|
|
49
50
|
inputSchema: z.object({ name: z.string().describe("Full fmsg address (@user@domain) or a short name") }),
|
|
50
51
|
outputSchema: z.object({ address: z.string(), resolution: z.enum(["literal", "directory", "default_domain"]) }),
|
|
51
52
|
annotations: { ...READ_ONLY, openWorldHint: false },
|
|
52
|
-
}, async ({ name }) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
}, async ({ name }, ctx) => {
|
|
54
|
+
const resolve = (resolver) => {
|
|
55
|
+
try {
|
|
56
|
+
const resolved = resolveAddress(name, resolver);
|
|
57
|
+
return ok(`${name} → ${resolved.address} (${resolved.resolution})`, resolved);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return toolError(error instanceof Error ? error.message : String(error));
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
// Only the caller's own domain needs the caller; otherwise resolution is local.
|
|
64
|
+
if (deps.config.defaultDomain !== CALLER_DOMAIN)
|
|
65
|
+
return resolve(deps.config);
|
|
66
|
+
return withCaller(deps, ctx, async (caller) => resolve(resolverFor(deps, caller)));
|
|
60
67
|
});
|
|
61
68
|
};
|
package/dist/tools/send.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as z from "zod/v4";
|
|
|
2
2
|
import { resolveAddresses, sameAddress } from "../address.js";
|
|
3
3
|
import { toolError } from "../errors.js";
|
|
4
4
|
import { isoTime, participantsOf } from "../render.js";
|
|
5
|
-
import { READ_ONLY, SENDS, idSchema, ok, withCaller } from "./common.js";
|
|
5
|
+
import { READ_ONLY, SENDS, idSchema, ok, resolverFor, withCaller } from "./common.js";
|
|
6
6
|
const IMMUTABLE = "fmsg messages are immutable: once sent they cannot be edited or recalled. Send within the user's requested task or authorized automation.";
|
|
7
7
|
const attachmentInput = z.object({
|
|
8
8
|
filename: z.string().regex(/^[A-Za-z0-9._-]+$/u, "letters, digits, dot, underscore, hyphen only"),
|
|
@@ -47,7 +47,7 @@ export const registerSendTools = (server, deps) => {
|
|
|
47
47
|
outputSchema: sentOutput,
|
|
48
48
|
annotations: SENDS,
|
|
49
49
|
}, async ({ to, topic, body, type, important, no_reply, attachments }, ctx) => withCaller(deps, ctx, async (caller, signal) => {
|
|
50
|
-
const recipients = resolveAddresses(to, deps
|
|
50
|
+
const recipients = resolveAddresses(to, resolverFor(deps, caller));
|
|
51
51
|
const sent = await caller.client.send({
|
|
52
52
|
to: recipients,
|
|
53
53
|
topic,
|
|
@@ -101,7 +101,7 @@ export const registerSendTools = (server, deps) => {
|
|
|
101
101
|
}
|
|
102
102
|
const warnings = [];
|
|
103
103
|
const to = recipients?.length
|
|
104
|
-
? resolveAddresses(recipients, deps
|
|
104
|
+
? resolveAddresses(recipients, resolverFor(deps, caller))
|
|
105
105
|
: participantsOf(parent).filter((a) => !sameAddress(a, caller.address));
|
|
106
106
|
if (to.length === 0)
|
|
107
107
|
return toolError(`message ${id} has no other participants to reply to; pass recipients`);
|
|
@@ -141,7 +141,7 @@ export const registerSendTools = (server, deps) => {
|
|
|
141
141
|
outputSchema: z.object({ id: z.string(), added: z.number(), add_to: z.array(z.string()) }),
|
|
142
142
|
annotations: { ...SENDS, idempotentHint: true },
|
|
143
143
|
}, async ({ id, add_to }, ctx) => withCaller(deps, ctx, async (caller, signal) => {
|
|
144
|
-
const addresses = resolveAddresses(add_to, deps
|
|
144
|
+
const addresses = resolveAddresses(add_to, resolverFor(deps, caller));
|
|
145
145
|
const result = await caller.client.addRecipients(id, addresses, signal);
|
|
146
146
|
return ok(`Added ${result.added} recipient(s) to message ${id}: ${addresses.join(", ")}`, { ...result, add_to: addresses });
|
|
147
147
|
}));
|
package/dist/tools/wait.js
CHANGED
|
@@ -3,7 +3,7 @@ import { resolveAddress } from "../address.js";
|
|
|
3
3
|
import { assembleThread, renderThread } from "../thread.js";
|
|
4
4
|
import { DATA_NOT_INSTRUCTIONS, fence, headerValue, messageData, messageLine } from "../render.js";
|
|
5
5
|
import { waitForMessage } from "../wait.js";
|
|
6
|
-
import { READ_ONLY, idSchema, messageItem, ok, toItem, withCaller } from "./common.js";
|
|
6
|
+
import { READ_ONLY, idSchema, messageItem, ok, resolverFor, toItem, withCaller } from "./common.js";
|
|
7
7
|
export const registerWaitTools = (server, deps) => {
|
|
8
8
|
const maxWait = deps.config.waitMaxSeconds;
|
|
9
9
|
server.registerTool("wait_for_message", {
|
|
@@ -41,7 +41,7 @@ export const registerWaitTools = (server, deps) => {
|
|
|
41
41
|
const result = await waitForMessage(caller.client, caller.address, {
|
|
42
42
|
...(after_id !== undefined ? { afterId: after_id } : {}),
|
|
43
43
|
...(thread_of !== undefined ? { threadOf: thread_of } : {}),
|
|
44
|
-
...(from !== undefined ? { from: resolveAddress(from, deps
|
|
44
|
+
...(from !== undefined ? { from: resolveAddress(from, resolverFor(deps, caller)).address } : {}),
|
|
45
45
|
timeoutMs: timeout_seconds * 1000,
|
|
46
46
|
settleMs: settle_seconds * 1000,
|
|
47
47
|
onTick: (elapsed) => {
|
package/docs/http-deployment.md
CHANGED
|
@@ -15,6 +15,11 @@ npx -y @markmnl/fmsg-mcp --http 127.0.0.1:8765
|
|
|
15
15
|
|
|
16
16
|
`FMSG_API_KEY` must be unset in HTTP mode. Include only browser origins you use.
|
|
17
17
|
|
|
18
|
+
When callers have addresses on several domains, set `FMSG_DEFAULT_DOMAIN=caller` rather than one
|
|
19
|
+
fixed domain: short names then resolve on each caller's own domain, so `bob` is `@bob@example.org`
|
|
20
|
+
for `@mark@example.org` and `@bob@example.net` for a caller on `example.net`. `whoami` and the
|
|
21
|
+
server instructions show that caller's domain. `FMSG_DIRECTORY` entries still take precedence.
|
|
22
|
+
|
|
18
23
|
If the server reaches the Web API at an internal address instead, for example
|
|
19
24
|
`FMSG_API_URL=http://10.0.0.5:8000` with `FMSG_ALLOW_INSECURE_HTTP=1` on a private network, also set
|
|
20
25
|
`FMSG_API_PUBLIC_URL=https://api.example.com` so `whoami` reports the URL users know. Without it,
|
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": "0.2.
|
|
4
|
+
"version": "0.2.5",
|
|
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": "0.2.
|
|
11
|
+
"version": "0.2.5",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
16
16
|
"identifier": "@markmnl/fmsg-mcp",
|
|
17
|
-
"version": "0.2.
|
|
17
|
+
"version": "0.2.5",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
20
20
|
},
|