@usefillo/mcp 0.7.0 → 0.8.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.
- package/README.md +8 -4
- package/dist/index.js +80 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,14 +98,18 @@ the named scope. With both, the login token wins — a key has no acting human.
|
|
|
98
98
|
| Destinations | `fillo_get_integration`, `fillo_enable_integration`, `fillo_disable_integration`, `fillo_list_connections`, `fillo_select_connection`, `fillo_disconnect_integration`, `fillo_remove_connection_account`, `fillo_rename_discord_channel`, `fillo_hubspot_properties`, `fillo_hubspot_pipelines` | `integrations:manage` |
|
|
99
99
|
| Responses and delivery | `fillo_list_held_responses`, `fillo_release_responses`, `fillo_delete_response`, `fillo_delivery_status`, `fillo_retry_deliveries`, `fillo_redeliver_responses`, `fillo_list_drafts`, `fillo_form_insights`, `fillo_list_respondents`, `fillo_delete_respondent` | `responses:manage`, `respondents:*`; `fillo_form_insights` needs `forms:read` **and** `responses:read` |
|
|
100
100
|
| Webhooks | `fillo_list_webhooks`, `fillo_add_webhook`, `fillo_update_webhook`, `fillo_remove_webhook` | `webhooks:manage` |
|
|
101
|
-
| Workspace | `fillo_rename_workspace`, `fillo_rename_project`, `fillo_get_branding`, `fillo_set_branding`, `fillo_list_members`, `fillo_invite_member`, `fillo_change_member_role`, `fillo_remove_member` | `workspace:manage`, `members:manage` |
|
|
101
|
+
| Workspace | `fillo_rename_workspace`, `fillo_rename_project`, `fillo_get_branding`, `fillo_set_branding`, `fillo_get_billing`, `fillo_list_members`, `fillo_invite_member`, `fillo_change_member_role`, `fillo_remove_member` | `workspace:manage`, `members:manage` |
|
|
102
102
|
| Credentials | `fillo_list_tokens`, `fillo_revoke_token`, `fillo_list_sync_tokens`, `fillo_create_sync_token`, `fillo_revoke_sync_token`, `fillo_list_api_keys`, `fillo_revoke_api_key`, `fillo_list_agents`, `fillo_revoke_agent` | `workspace:manage` |
|
|
103
103
|
| Developer settings | `fillo_get_code_sync_policy`, `fillo_set_code_sync_policy`, `fillo_get_origins`, `fillo_set_origins`, `fillo_identity_status`, `fillo_enable_identity`, `fillo_disable_identity` | `workspace:manage` |
|
|
104
104
|
|
|
105
105
|
`fillo_delete_form`, `fillo_get_branding`, `fillo_set_branding`,
|
|
106
|
-
`fillo_list_api_keys`, and `fillo_revoke_api_key` need a
|
|
107
|
-
no project-API-key route for them, so a leaked key can
|
|
108
|
-
the workspace's credentials
|
|
106
|
+
`fillo_get_billing`, `fillo_list_api_keys`, and `fillo_revoke_api_key` need a
|
|
107
|
+
login token — there is no project-API-key route for them, so a leaked key can
|
|
108
|
+
never enumerate or revoke the workspace's credentials or read its plan.
|
|
109
|
+
`fillo_get_billing` is read-only: it reports the plan and this month's usage and
|
|
110
|
+
returns the Settings link, but no tool can subscribe, change the plan, start a
|
|
111
|
+
trial, or open checkout — an owner or admin does that in Settings → Billing &
|
|
112
|
+
plan. `fillo_delete_response` needs one too, for a
|
|
109
113
|
different reason: its scoped route takes no typed confirmation, so on a project
|
|
110
114
|
API key the confirmation would be checked only by the caller, which is no
|
|
111
115
|
confirmation at all.
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/
|
|
3
|
+
// src/telemetry.ts
|
|
4
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
4
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
+
var toolContext = new AsyncLocalStorage();
|
|
7
|
+
function currentTool() {
|
|
8
|
+
return toolContext.getStore();
|
|
9
|
+
}
|
|
10
|
+
var ObservedMcpServer = class extends McpServer {
|
|
11
|
+
registerTool(name, config, cb) {
|
|
12
|
+
const wrapped = new Proxy(cb, {
|
|
13
|
+
apply(target, thisArg, args) {
|
|
14
|
+
return toolContext.run(name, () => Reflect.apply(target, thisArg, args));
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return super.registerTool(name, config, wrapped);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
5
22
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
23
|
|
|
7
24
|
// src/config.ts
|
|
@@ -202,6 +219,8 @@ async function filloFetch(path, init = {}) {
|
|
|
202
219
|
const query = init.searchParams?.toString();
|
|
203
220
|
const url = `${apiOrigin()}${path}${query ? `?${query}` : ""}`;
|
|
204
221
|
const headers = { "X-Fillo-Client": CLIENT_VERSION };
|
|
222
|
+
const tool = currentTool();
|
|
223
|
+
if (tool) headers["X-Fillo-Tool"] = tool;
|
|
205
224
|
if (init.body !== void 0) headers["Content-Type"] = "application/json";
|
|
206
225
|
if (init.token) headers.Authorization = `Bearer ${init.token}`;
|
|
207
226
|
const res = await fetch(url, {
|
|
@@ -2504,6 +2523,7 @@ function registerWorkspaceAdmin(server) {
|
|
|
2504
2523
|
registerRenameProject(server);
|
|
2505
2524
|
registerGetBranding(server);
|
|
2506
2525
|
registerSetBranding(server);
|
|
2526
|
+
registerGetBilling(server);
|
|
2507
2527
|
registerListMembers(server);
|
|
2508
2528
|
registerInviteMember(server);
|
|
2509
2529
|
registerSetMemberRole(server);
|
|
@@ -2637,6 +2657,64 @@ function registerSetBranding(server) {
|
|
|
2637
2657
|
}
|
|
2638
2658
|
);
|
|
2639
2659
|
}
|
|
2660
|
+
var LONG_DATE = new Intl.DateTimeFormat("en-GB", {
|
|
2661
|
+
day: "numeric",
|
|
2662
|
+
month: "long",
|
|
2663
|
+
year: "numeric",
|
|
2664
|
+
timeZone: "UTC"
|
|
2665
|
+
});
|
|
2666
|
+
var COUNT = new Intl.NumberFormat("en-US");
|
|
2667
|
+
function isoDate(value) {
|
|
2668
|
+
if (typeof value !== "string") return null;
|
|
2669
|
+
const date = new Date(value);
|
|
2670
|
+
return Number.isNaN(date.getTime()) ? null : LONG_DATE.format(date);
|
|
2671
|
+
}
|
|
2672
|
+
function billingSummary(json) {
|
|
2673
|
+
const tier = typeof json?.tier === "string" ? `Everything ${json.tier}` : "Everything";
|
|
2674
|
+
const plan = json?.plan === "free" ? "Free" : json?.plan === "trial" ? `${tier} trial` : json?.plan === "complimentary" ? `${tier}, complimentary` : json?.plan === "subscribed" ? `${tier}, billed ${json.interval === "year" ? "yearly" : "monthly"}` : "Plan unknown";
|
|
2675
|
+
const parts = [plan];
|
|
2676
|
+
const usage = json?.usage;
|
|
2677
|
+
if (typeof usage?.responses === "number" && typeof json?.allowance === "number") {
|
|
2678
|
+
parts.push(
|
|
2679
|
+
`${COUNT.format(usage.responses)} of ${COUNT.format(json.allowance)} responses this month`
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
const periodEnd = isoDate(json?.currentPeriodEnd);
|
|
2683
|
+
const trialEnd = isoDate(json?.trialEndsAt);
|
|
2684
|
+
if (json?.plan === "subscribed" && json.status === "past_due") {
|
|
2685
|
+
parts.push("the last payment failed; Stripe is retrying");
|
|
2686
|
+
} else if (json?.plan === "subscribed" && periodEnd) {
|
|
2687
|
+
parts.push(json.cancelAtPeriodEnd ? `cancels ${periodEnd}` : `renews ${periodEnd}`);
|
|
2688
|
+
} else if (json?.plan === "trial" && trialEnd) {
|
|
2689
|
+
parts.push(`trial ends ${trialEnd}`);
|
|
2690
|
+
}
|
|
2691
|
+
const manageUrl = typeof json?.manageUrl === "string" && /^https?:\/\//u.test(json.manageUrl) ? `: ${json.manageUrl}` : "";
|
|
2692
|
+
return `${parts.join(" \xB7 ")}. Plan changes are made by an owner or admin in Settings \u2192 Billing & plan${manageUrl}`;
|
|
2693
|
+
}
|
|
2694
|
+
function registerGetBilling(server) {
|
|
2695
|
+
server.registerTool(
|
|
2696
|
+
"fillo_get_billing",
|
|
2697
|
+
{
|
|
2698
|
+
title: "Read the workspace's plan and usage",
|
|
2699
|
+
description: "Report the workspace's plan (Free, trial, complimentary, or an Everything volume and billing period), this month's response count against its allowance, recent monthly usage, and the Settings link where an owner or admin changes the plan. Read-only: no tool can subscribe, change the plan, start a trial, or open checkout \u2014 report the numbers and hand the human manageUrl. Needs a LOGIN TOKEN \u2014 billing has no project-API-key route.",
|
|
2700
|
+
inputSchema: {},
|
|
2701
|
+
annotations: READ_ONLY
|
|
2702
|
+
},
|
|
2703
|
+
async () => {
|
|
2704
|
+
const lane = resolveLane();
|
|
2705
|
+
if (!lane) return noCredential("(login token only)");
|
|
2706
|
+
if (lane.kind !== "cli") return LOGIN_ONLY("Reading the plan and usage");
|
|
2707
|
+
const res = await laneFetch(lane, { path: "/workspace/billing" });
|
|
2708
|
+
const problem = laneProblem(lane, res, {
|
|
2709
|
+
scope: "(login token only)",
|
|
2710
|
+
fallback: "Couldn't read the plan and usage",
|
|
2711
|
+
missing: "This Fillo server doesn't report billing yet. Open Settings \u2192 Billing & plan to see the plan and usage."
|
|
2712
|
+
});
|
|
2713
|
+
if (problem) return problem;
|
|
2714
|
+
return ok(billingSummary(res.json), res.json);
|
|
2715
|
+
}
|
|
2716
|
+
);
|
|
2717
|
+
}
|
|
2640
2718
|
function registerInviteMember(server) {
|
|
2641
2719
|
server.registerTool(
|
|
2642
2720
|
"fillo_invite_member",
|
|
@@ -3273,7 +3351,7 @@ function registerTools(server) {
|
|
|
3273
3351
|
// src/index.ts
|
|
3274
3352
|
async function main() {
|
|
3275
3353
|
const version = CLIENT_VERSION.split("@").pop() ?? "0.0.0";
|
|
3276
|
-
const server = new
|
|
3354
|
+
const server = new ObservedMcpServer({ name: "fillo", version });
|
|
3277
3355
|
registerTools(server);
|
|
3278
3356
|
const transport = new StdioServerTransport();
|
|
3279
3357
|
await server.connect(transport);
|
package/package.json
CHANGED