@50heads/mcp 2026.925.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.
@@ -0,0 +1,100 @@
1
+ // src/snippets.ts
2
+ var CLIENTS = ["claude-desktop", "claude-code", "cursor", "chatgpt", "vscode", "windsurf", "generic"];
3
+ var json = (v) => JSON.stringify(v, null, 2);
4
+ function configSnippets(options = {}) {
5
+ const url = options.url ?? "https://mcp.50heads.com/mcp";
6
+ const key = options.apiKey ?? "fh_live_\u2026";
7
+ const npx = { command: "npx", args: ["-y", "@50heads/mcp"], env: { FIFTYHEADS_API_KEY: key } };
8
+ return [
9
+ {
10
+ client: "claude-desktop",
11
+ title: "Claude (claude.ai and Claude Desktop)",
12
+ where: "Settings, Connectors, Add custom connector. Paste the URL and sign in when asked. On Team and Enterprise plans an owner adds it for the organisation first.",
13
+ auth: "oauth",
14
+ format: "text",
15
+ body: url,
16
+ alternative: {
17
+ where: "Or with an API key, in claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\\Claude\\).",
18
+ format: "json",
19
+ body: json({ mcpServers: { "50heads": npx } })
20
+ }
21
+ },
22
+ {
23
+ client: "claude-code",
24
+ title: "Claude Code",
25
+ where: "Run in a terminal, then /mcp in Claude Code to sign in.",
26
+ auth: "oauth",
27
+ format: "shell",
28
+ body: `claude mcp add --transport http 50heads ${url}`,
29
+ alternative: {
30
+ where: "Or with an API key (CI and scripts):",
31
+ format: "shell",
32
+ body: `claude mcp add --transport http 50heads ${url} --header "Authorization: Bearer ${key}"`
33
+ }
34
+ },
35
+ {
36
+ client: "cursor",
37
+ title: "Cursor",
38
+ where: "~/.cursor/mcp.json (or .cursor/mcp.json in a project). Cursor opens the sign-in page.",
39
+ auth: "oauth",
40
+ format: "json",
41
+ body: json({ mcpServers: { "50heads": { url } } }),
42
+ alternative: {
43
+ where: "Or with an API key:",
44
+ format: "json",
45
+ body: json({ mcpServers: { "50heads": { url, headers: { Authorization: `Bearer ${key}` } } } })
46
+ }
47
+ },
48
+ {
49
+ client: "chatgpt",
50
+ title: "ChatGPT",
51
+ where: "Settings, Apps and Connectors, Advanced settings, turn on Developer mode, then Create. Paste the URL and choose OAuth. On Business and Enterprise plans an admin turns on Developer mode first.",
52
+ auth: "oauth",
53
+ format: "text",
54
+ body: url
55
+ },
56
+ {
57
+ client: "vscode",
58
+ title: "VS Code",
59
+ where: ".vscode/mcp.json in the workspace, or MCP: Add Server from the command palette.",
60
+ auth: "oauth",
61
+ format: "json",
62
+ body: json({ servers: { "50heads": { type: "http", url } } }),
63
+ alternative: {
64
+ where: "Or from a terminal:",
65
+ format: "shell",
66
+ body: `code --add-mcp '${JSON.stringify({ name: "50heads", type: "http", url })}'`
67
+ }
68
+ },
69
+ {
70
+ client: "windsurf",
71
+ title: "Windsurf",
72
+ where: "~/.codeium/windsurf/mcp_config.json, or Windsurf Settings, Cascade, MCP servers, View raw config.",
73
+ auth: "key",
74
+ format: "json",
75
+ body: json({ mcpServers: { "50heads": npx } }),
76
+ alternative: {
77
+ where: "Or the hosted server with an API key:",
78
+ format: "json",
79
+ body: json({ mcpServers: { "50heads": { serverUrl: url, headers: { Authorization: `Bearer ${key}` } } } })
80
+ }
81
+ },
82
+ {
83
+ client: "generic",
84
+ title: "Any other host",
85
+ where: "Hosts that launch a local command. Needs Node 20 or later and an API key from the dashboard.",
86
+ auth: "key",
87
+ format: "shell",
88
+ body: `FIFTYHEADS_API_KEY=${key} npx -y @50heads/mcp`,
89
+ alternative: {
90
+ where: `Hosts that speak Streamable HTTP: ${url} with the header "Authorization: Bearer ${key}", or OAuth.`,
91
+ format: "json",
92
+ body: json({ mcpServers: { "50heads": { url, headers: { Authorization: `Bearer ${key}` } } } })
93
+ }
94
+ }
95
+ ];
96
+ }
97
+ export {
98
+ CLIENTS,
99
+ configSnippets
100
+ };
@@ -0,0 +1,22 @@
1
+ import { type Rates } from "@50heads/shared";
2
+ import type { Client } from "@50heads/shared/client";
3
+ import { type Currency } from "./pricing.js";
4
+ export type Money = {
5
+ currency: Currency;
6
+ rates: Rates;
7
+ };
8
+ /**
9
+ * The account's display currency and the day's rates, each fetched at most once per server
10
+ * (one request on HTTP, one connection on stdio) and shared by every tool, resource and task.
11
+ * The currency comes from the billing balance; when that cannot be read (signed out, no
12
+ * account:read, or the API failed) it is UNKNOWN_CURRENCY, never a silent pound. A failed read
13
+ * is not cached, so the next call tries again. An explicit currency argument always wins.
14
+ */
15
+ export declare function accountMoney(api: (tag: string) => Client, canReadAccount: boolean): {
16
+ rates: () => Promise<Rates>;
17
+ currency: (explicit?: Currency | null) => Promise<Currency>;
18
+ /** Both, in parallel. */
19
+ money: (explicit?: Currency | null) => Promise<Money>;
20
+ /** Records a currency already read (the balance tool), so no second request is made. */
21
+ remember(c: Currency): void;
22
+ };
@@ -0,0 +1,53 @@
1
+ import type { Client } from "@50heads/shared/client";
2
+ import { type HelpSearchEntry } from "@50heads/shared/help-search";
3
+ import { type BuildAskLinkInput, type GetAnswersOutput } from "./schemas.js";
4
+ /**
5
+ * Helpers behind the tools added for PickFu parity: image upload, answer pages, the pre-filled
6
+ * ask link, the help index and targeting. Pure where possible, so they are tested directly.
7
+ */
8
+ /** The real image type of some bytes, or null (JPEG, PNG and WebP only, like the API). */
9
+ export declare function sniffImage(b: Uint8Array): "image/jpeg" | "image/png" | "image/webp" | null;
10
+ /** base64 (or a data: URL) → bytes and type, with the reason in plain words when it fails. */
11
+ export declare function decodeImage(data: string, declared?: string): {
12
+ bytes: Uint8Array;
13
+ contentType: string;
14
+ };
15
+ export type AnswerFilter = {
16
+ option?: number;
17
+ tier?: number;
18
+ country?: string;
19
+ age_band?: string;
20
+ gender?: string;
21
+ q?: string;
22
+ };
23
+ /** The filter as the API's query names (analysis.ts RESULT_FILTER_PARAMS). */
24
+ export declare function filterParams(f: AnswerFilter): Record<string, string>;
25
+ /**
26
+ * A page of answers. Uses the API's filtered, paginated answers endpoint when this API has it;
27
+ * otherwise reads the result and filters and pages here (option, tier and keyword; country and
28
+ * age band need the server, which can check that a segment is big enough to show).
29
+ */
30
+ export declare function answersPage(api: Client, questionId: string, filter: AnswerFilter, page: {
31
+ limit: number;
32
+ cursor?: string;
33
+ }): Promise<GetAnswersOutput>;
34
+ /**
35
+ * The portal composer's query parameters (apps/web/app/lib/portal/composer.ts draftFromForm and
36
+ * the ask loader). Documented in the help centre and on /docs/mcp; keep the three in step.
37
+ */
38
+ export declare function buildAskLink(portalUrl: string, input: BuildAskLinkInput): {
39
+ url: string;
40
+ params: {
41
+ name: string;
42
+ value: string;
43
+ }[];
44
+ notes: string[];
45
+ };
46
+ /** The published help index for a locale (/search/<locale>.json), cached for an hour. */
47
+ export declare function helpIndex(webUrl: string, locale: string, fetchImpl: typeof fetch): Promise<HelpSearchEntry[]>;
48
+ export declare function searchHelp(entries: HelpSearchEntry[], query: string, limit: number, webUrl: string): {
49
+ title: string;
50
+ section: string;
51
+ excerpt: string;
52
+ url: string;
53
+ }[];
@@ -0,0 +1,22 @@
1
+ /**
2
+ * MCP Apps (io.modelcontextprotocol/apps) views: the quote card for `estimate` and the results
3
+ * view for `get_results` and the results resource. Each is one self-contained HTML document:
4
+ * brand tokens inline, no external requests (fonts fall back to the brand's stacks), under
5
+ * 30 KB. They talk to the host over the MCP Apps postMessage protocol and also read
6
+ * `window.openai.toolOutput` on hosts that expose it.
7
+ */
8
+ export declare const APP_MIME_TYPE = "text/html;profile=mcp-app";
9
+ export declare const RESULTS_VIEW_URI = "ui://50heads/results.html";
10
+ export declare const QUOTE_VIEW_URI = "ui://50heads/quote.html";
11
+ /** The results view: winner line, bars, confidence, a follow-up button. */
12
+ export declare function resultsViewHtml(): string;
13
+ /** The quote card: cost and time in one sentence, the breakdown, fixes, an ask button. */
14
+ export declare function quoteViewHtml(): string;
15
+ /** `_meta` a tool or resource carries to declare its view. */
16
+ export declare function uiMeta(uri: string): {
17
+ ui: {
18
+ resourceUri: string;
19
+ };
20
+ "ui/resourceUri": string;
21
+ "openai/outputTemplate": string;
22
+ };