@utilix-tech/mcp 0.34.0 → 0.36.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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  Full release notes for all Utilix surfaces (browser tools, REST API, SDKs, MCP server) live at [utilix.tech/changelog](https://utilix.tech/changelog). This file tracks just this package.
4
4
 
5
+ ## 0.36.0
6
+ - Add `calculate_roi` tool: return on investment percent from an initial and final value, plus the annualized (CAGR) return given an optional holding period in years.
7
+ - Add `lookup_emoji` tool: search a curated table of ~280 common emoji by name, keyword, or GitHub-style shortcode, or look one up exactly by shortcode, character, or category.
8
+
9
+ ## 0.35.0
10
+ - Add `build_referrer_policy` tool: build a Referrer-Policy header value from one or more policy tokens with a plain-English explanation of each and warnings for risky choices like unsafe-url.
11
+ - Add `generate_markdown_toc` tool: scan a Markdown document's ATX headings and build a nested table of contents with GitHub-style anchor slugs, disambiguating duplicates.
12
+
5
13
  ## 0.34.0
6
14
  - Add `lint_conventional_commit` tool: lint a git commit message against the Conventional Commits v1.0.0 spec, checking header format, blank-line separation, footer tokens, and BREAKING CHANGE casing.
7
15
  - Add `calculate_savings_goal` tool: solve for months to reach a savings goal at a fixed monthly contribution, or the monthly contribution required to hit a goal by a target month count.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @utilix-tech/mcp
2
2
 
3
- MCP server exposing 154 developer utility tools to Claude, Cursor, VS Code Copilot, and any [Model Context Protocol](https://modelcontextprotocol.io) compatible AI assistant.
3
+ MCP server exposing 158 developer utility tools to Claude, Cursor, VS Code Copilot, and any [Model Context Protocol](https://modelcontextprotocol.io) compatible AI assistant.
4
4
 
5
5
  No API key required. All tools run locally. Requires Node.js 18 or later.
6
6
 
@@ -128,7 +128,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
128
128
  | `generate_qr` | Generate a QR code as an SVG string |
129
129
  | `generate_random_data` | Generate random mock data: names, emails, UUIDs, IPs, etc. |
130
130
 
131
- ### Text (14 tools)
131
+ ### Text (15 tools)
132
132
  | Tool | Description |
133
133
  |------|-------------|
134
134
  | `convert_case` | Convert text case: camelCase, snake_case, PascalCase, etc. |
@@ -145,6 +145,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
145
145
  | `detect_filler_words` | Scan text for filler words, hedge phrases, and clichés with per-phrase counts and a density score |
146
146
  | `calculate_string_distance` | Compute the Levenshtein (or Damerau) edit distance and normalized similarity between two strings |
147
147
  | `analyze_sentence_lengths` | Split text into sentences and report a histogram of sentence lengths, plus mean, median, standard deviation, and a consistency label |
148
+ | `lookup_emoji` | Search a curated table of ~280 common emoji by name, keyword, or GitHub-style shortcode, or look one up exactly by shortcode, character, or category |
148
149
 
149
150
  ### Time (6 tools)
150
151
  | Tool | Description |
@@ -156,7 +157,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
156
157
  | `convert_timezone` | Convert a date/time between timezones |
157
158
  | `convert_iso8601_duration` | Parse an ISO 8601 duration into components and total seconds, or format seconds into a duration string |
158
159
 
159
- ### Units (22 tools)
160
+ ### Units (23 tools)
160
161
  | Tool | Description |
161
162
  |------|-------------|
162
163
  | `convert_bytes` | Convert between B, KB, MB, GB, TB, KiB, MiB, GiB, TiB |
@@ -181,8 +182,9 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
181
182
  | `calculate_rule_of_72` | Estimate years to double an investment from a rate, or the rate needed to double in a given number of years, via the Rule of 72 shortcut and the exact logarithmic result |
182
183
  | `calculate_emi` | Compute the Equated Monthly Installment for a loan from principal, annual rate, and tenure in years or months, with a year-by-year principal/interest breakdown |
183
184
  | `calculate_savings_goal` | Solve for months to reach a savings goal at a fixed monthly contribution, or the monthly contribution required to hit a goal by a target month count |
185
+ | `calculate_roi` | Compute return on investment percent from an initial and final value, plus the annualized (CAGR) return given an optional holding period in years |
184
186
 
185
- ### API / Network (12 tools)
187
+ ### API / Network (13 tools)
186
188
  | Tool | Description |
187
189
  |------|-------------|
188
190
  | `decode_jwt` | Decode a JWT: header, payload, and expiry |
@@ -196,6 +198,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
196
198
  | `validate_robots_txt` | Validate a robots.txt file: User-agent groups, rules, and directive syntax |
197
199
  | `parse_user_agent` | Parse a browser User-Agent string into browser, engine, OS, and device type |
198
200
  | `build_cache_control` | Build and explain an HTTP Cache-Control response header from directives (max-age, no-store, immutable, etc.) |
201
+ | `build_referrer_policy` | Build and explain an HTTP Referrer-Policy header from one or more fallback-chain policy tokens |
199
202
  | `parse_ipv6_address` | Expand an IPv6 address to its full 8-group form or compress it to its RFC 5952 canonical shortest form, classify its address type, and handle an embedded IPv4 suffix or zone ID |
200
203
 
201
204
  ### Color (4 tools)
@@ -221,7 +224,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
221
224
  | `detect_redos` | Statically flag catastrophic-backtracking (ReDoS) risk in a regex: nested quantifiers, overlapping alternation, adjacent overlapping quantifiers |
222
225
  | `lint_conventional_commit` | Lint a commit message against the Conventional Commits v1.0.0 spec: header format, blank-line separation, footer tokens, and BREAKING CHANGE casing |
223
226
 
224
- ### Data (7 tools)
227
+ ### Data (8 tools)
225
228
  | Tool | Description |
226
229
  |------|-------------|
227
230
  | `validate_yaml` | Validate YAML syntax |
@@ -231,6 +234,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
231
234
  | `format_ndjson` | Validate and pretty-print newline-delimited JSON (NDJSON) |
232
235
  | `diff_env_example` | Diff a .env file against its .env.example template: flags keys missing from either side, plus empty placeholder values |
233
236
  | `parse_markdown_front_matter` | Split a Markdown document into its YAML front matter fields and body content |
237
+ | `generate_markdown_toc` | Scan a Markdown document's ATX headings and build a nested table of contents with GitHub-style anchor slugs |
234
238
 
235
239
  ### CSS (2 tools)
236
240
  | Tool | Description |
package/dist/index.js CHANGED
@@ -4157,6 +4157,66 @@ server.tool(
4157
4157
  return text(JSON.stringify(result, null, 2));
4158
4158
  }
4159
4159
  );
4160
+ var _REFERRER_POLICY_VALUES_MCP = [
4161
+ "no-referrer",
4162
+ "no-referrer-when-downgrade",
4163
+ "origin",
4164
+ "origin-when-cross-origin",
4165
+ "same-origin",
4166
+ "strict-origin",
4167
+ "strict-origin-when-cross-origin",
4168
+ "unsafe-url"
4169
+ ];
4170
+ var _REFERRER_POLICY_INFO_MCP = {
4171
+ "no-referrer": { explanation: "Never sends the Referer header, on any request. The strictest option; the destination learns nothing about where the request came from.", leaksPathAndQuery: false, sentOnDowngrade: false },
4172
+ "no-referrer-when-downgrade": { explanation: "Sends the full URL (origin, path, and query string) for same-security-level or upgrading requests, but omits the header entirely when navigating from HTTPS to HTTP. This was the legacy browser default before strict-origin-when-cross-origin.", leaksPathAndQuery: true, sentOnDowngrade: false },
4173
+ origin: { explanation: "Sends only the origin (scheme, host, and port) on every request, same-origin or cross-origin, including on a downgrade. The path and query string are always stripped.", leaksPathAndQuery: false, sentOnDowngrade: true },
4174
+ "origin-when-cross-origin": { explanation: "Sends the full URL for same-origin requests, but only the origin for cross-origin requests. Still sends the origin on a downgrade.", leaksPathAndQuery: true, sentOnDowngrade: true },
4175
+ "same-origin": { explanation: "Sends the full URL for same-origin requests, and no Referer header at all for cross-origin requests.", leaksPathAndQuery: true, sentOnDowngrade: false },
4176
+ "strict-origin": { explanation: "Sends only the origin, and only when the security level stays the same or improves (HTTPS to HTTPS, or HTTP to anything). Nothing is sent on a downgrade from HTTPS to HTTP.", leaksPathAndQuery: false, sentOnDowngrade: false },
4177
+ "strict-origin-when-cross-origin": { explanation: "Sends the full URL for same-origin requests, only the origin for cross-origin requests at the same or better security level, and nothing at all on a downgrade. This is the current browser default when no policy is set.", leaksPathAndQuery: true, sentOnDowngrade: false },
4178
+ "unsafe-url": { explanation: "Always sends the full URL, including path and query string, on every request, even on a downgrade from HTTPS to HTTP. Generally discouraged: query strings can carry session tokens or other sensitive data that then leaks to third-party destinations and to the network on an insecure connection.", leaksPathAndQuery: true, sentOnDowngrade: true }
4179
+ };
4180
+ function _buildReferrerPolicyMcp(policies) {
4181
+ const trimmed = policies.map((p) => p.trim()).filter((p) => p !== "");
4182
+ if (trimmed.length === 0) return { error: "At least one policy value is required" };
4183
+ const entries = [];
4184
+ for (const value of trimmed) {
4185
+ if (!_REFERRER_POLICY_VALUES_MCP.includes(value)) {
4186
+ return { error: `'${value}' is not a valid Referrer-Policy value. Valid values: ${_REFERRER_POLICY_VALUES_MCP.join(", ")}` };
4187
+ }
4188
+ entries.push({ value, ..._REFERRER_POLICY_INFO_MCP[value] });
4189
+ }
4190
+ const warnings = [];
4191
+ const last = entries[entries.length - 1];
4192
+ if (last.value === "unsafe-url") {
4193
+ warnings.push("unsafe-url sends the full URL, including query strings, on every request, even over an insecure downgrade. Prefer strict-origin-when-cross-origin unless you have a specific reason to leak full URLs.");
4194
+ }
4195
+ if (entries.length > 1 && entries.some((e, i) => i !== entries.length - 1 && e.value === last.value)) {
4196
+ warnings.push("The same policy value appears more than once in the fallback chain, which has no effect beyond the first occurrence.");
4197
+ }
4198
+ const header = entries.map((e) => e.value).join(", ");
4199
+ return {
4200
+ header,
4201
+ headerName: "Referrer-Policy",
4202
+ snippet: `Referrer-Policy: ${header}`,
4203
+ metaTag: `<meta name="referrer" content="${last.value}">`,
4204
+ policies: entries,
4205
+ warnings
4206
+ };
4207
+ }
4208
+ server.tool(
4209
+ "build_referrer_policy",
4210
+ "Build an HTTP Referrer-Policy response-header value from one or more policy tokens (a fallback chain per the Referrer Policy spec), with a plain-English explanation of each token and warnings for risky choices like unsafe-url. Pure string assembly and lookup, not validated against live request traffic.",
4211
+ {
4212
+ policies: z.array(z.enum(_REFERRER_POLICY_VALUES_MCP)).min(1).describe('One or more Referrer-Policy tokens forming a fallback chain, e.g. ["strict-origin-when-cross-origin"]')
4213
+ },
4214
+ async ({ policies }) => {
4215
+ const result = _buildReferrerPolicyMcp(policies);
4216
+ if ("error" in result) return errText(result);
4217
+ return text(JSON.stringify(result, null, 2));
4218
+ }
4219
+ );
4160
4220
  function _isValidIpv6HexGroup(g) {
4161
4221
  return /^[0-9a-fA-F]{1,4}$/.test(g);
4162
4222
  }
@@ -5638,6 +5698,76 @@ server.tool(
5638
5698
  return text(JSON.stringify(result, null, 2));
5639
5699
  }
5640
5700
  );
5701
+ function _stripInlineMarkdownMcp(text2) {
5702
+ return text2.replace(/(\*\*\*|___)(.+?)\1/g, "$2").replace(/(\*\*|__)(.+?)\1/g, "$2").replace(/(\*|_)(.+?)\1/g, "$2").replace(/`([^`]+)`/g, "$1").replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").trim();
5703
+ }
5704
+ function _slugifyHeadingMcp(text2, seen) {
5705
+ let slug = text2.toLowerCase().trim().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s/g, "-");
5706
+ const count = seen.get(slug) ?? 0;
5707
+ seen.set(slug, count + 1);
5708
+ if (count > 0) slug = `${slug}-${count}`;
5709
+ return slug;
5710
+ }
5711
+ function _generateMarkdownTocMcp(markdown, minLevel, maxLevel, ordered) {
5712
+ if (typeof markdown !== "string" || markdown.trim() === "") return { error: "markdown is required" };
5713
+ if (!Number.isInteger(minLevel) || !Number.isInteger(maxLevel) || minLevel < 1 || minLevel > 6 || maxLevel < 1 || maxLevel > 6 || minLevel > maxLevel) {
5714
+ return { error: "minLevel and maxLevel must be integers between 1 and 6, with minLevel <= maxLevel" };
5715
+ }
5716
+ const lines = markdown.replace(/\r\n/g, "\n").split("\n");
5717
+ const entries = [];
5718
+ const seen = /* @__PURE__ */ new Map();
5719
+ let inFence = false;
5720
+ let fenceMarker = "";
5721
+ for (const line of lines) {
5722
+ const fenceMatch = line.match(/^\s*(```+|~~~+)/);
5723
+ if (fenceMatch) {
5724
+ if (!inFence) {
5725
+ inFence = true;
5726
+ fenceMarker = fenceMatch[1][0];
5727
+ } else if (fenceMatch[1][0] === fenceMarker) {
5728
+ inFence = false;
5729
+ }
5730
+ continue;
5731
+ }
5732
+ if (inFence) continue;
5733
+ const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*#*\s*$/);
5734
+ if (!headingMatch) continue;
5735
+ const level = headingMatch[1].length;
5736
+ const text2 = _stripInlineMarkdownMcp(headingMatch[2]);
5737
+ if (text2 === "") continue;
5738
+ const slug = _slugifyHeadingMcp(text2, seen);
5739
+ if (level < minLevel || level > maxLevel) continue;
5740
+ entries.push({ level, text: text2, slug });
5741
+ }
5742
+ if (entries.length === 0) return { error: "No headings found in the given level range" };
5743
+ const baseLevel = Math.min(...entries.map((e) => e.level));
5744
+ const counters = [0, 0, 0, 0, 0, 0, 0];
5745
+ const tocLines = entries.map((e) => {
5746
+ const indent = " ".repeat(e.level - baseLevel);
5747
+ if (ordered) {
5748
+ counters[e.level] = (counters[e.level] ?? 0) + 1;
5749
+ for (let l = e.level + 1; l < counters.length; l++) counters[l] = 0;
5750
+ return `${indent}${counters[e.level]}. [${e.text}](#${e.slug})`;
5751
+ }
5752
+ return `${indent}- [${e.text}](#${e.slug})`;
5753
+ });
5754
+ return { toc: tocLines.join("\n"), entries };
5755
+ }
5756
+ server.tool(
5757
+ "generate_markdown_toc",
5758
+ "Scan a Markdown document's ATX headings (# through ######) and build a nested table of contents with GitHub-style anchor slugs, disambiguating duplicate headings with -1, -2, ... suffixes. Setext-style headings are not recognized, and headings inside fenced code blocks are ignored.",
5759
+ {
5760
+ markdown: z.string().describe("The Markdown document to scan for headings"),
5761
+ minLevel: z.number().int().min(1).max(6).optional().describe("Shallowest heading level to include, defaults to 1"),
5762
+ maxLevel: z.number().int().min(1).max(6).optional().describe("Deepest heading level to include, defaults to 6"),
5763
+ ordered: z.boolean().optional().describe("Render as a numbered list instead of a bullet list, defaults to false")
5764
+ },
5765
+ async ({ markdown, minLevel, maxLevel, ordered }) => {
5766
+ const result = _generateMarkdownTocMcp(markdown, minLevel ?? 1, maxLevel ?? 6, ordered ?? false);
5767
+ if ("error" in result) return errText(result);
5768
+ return text(JSON.stringify(result, null, 2));
5769
+ }
5770
+ );
5641
5771
  var _COMMIT_DEFAULT_TYPES_MCP = ["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test"];
5642
5772
  var _COMMIT_HEADER_RE_MCP = /^([A-Za-z][A-Za-z0-9-]*)(\(([^()]*)\))?(!)?: (.+)$/;
5643
5773
  var _COMMIT_FOOTER_LINE_RE_MCP = /^([A-Za-z][A-Za-z0-9-]*|BREAKING CHANGE)(: ?| #)(.*)$/;
@@ -5851,5 +5981,363 @@ server.tool(
5851
5981
  return text(JSON.stringify(result, null, 2));
5852
5982
  }
5853
5983
  );
5984
+ function _calculateRoiMcp(initialValue, finalValue, years) {
5985
+ if (typeof initialValue !== "number" || !Number.isFinite(initialValue) || initialValue <= 0) {
5986
+ return { error: "initialValue must be a finite number greater than zero" };
5987
+ }
5988
+ if (typeof finalValue !== "number" || !Number.isFinite(finalValue) || finalValue < 0) {
5989
+ return { error: "finalValue must be a finite, non-negative number" };
5990
+ }
5991
+ const round4 = (n) => Math.round(n * 1e4) / 1e4;
5992
+ const profit = finalValue - initialValue;
5993
+ const roiPercent = profit / initialValue * 100;
5994
+ const result = {
5995
+ initialValue: round4(initialValue),
5996
+ finalValue: round4(finalValue),
5997
+ profit: round4(profit),
5998
+ roiPercent: round4(roiPercent)
5999
+ };
6000
+ if (years !== void 0) {
6001
+ if (typeof years !== "number" || !Number.isFinite(years) || years <= 0) {
6002
+ return { error: "years must be a finite number greater than zero when provided" };
6003
+ }
6004
+ const annualizedReturnPercent = (Math.pow(finalValue / initialValue, 1 / years) - 1) * 100;
6005
+ result.years = round4(years);
6006
+ result.annualizedReturnPercent = round4(annualizedReturnPercent);
6007
+ }
6008
+ return result;
6009
+ }
6010
+ server.tool(
6011
+ "calculate_roi",
6012
+ "Compute return on investment as a percentage from an initial and final value, and optionally the annualized return given a holding period in years. Unlike the present-value or compound-interest calculators, which grow a sum at a known rate, this derives the realized rate from actual start/end values. Pure arithmetic, no live rate feed.",
6013
+ {
6014
+ initialValue: z.number().describe("The starting investment value (must be greater than zero)"),
6015
+ finalValue: z.number().describe("The ending investment value (cannot be negative)"),
6016
+ years: z.number().optional().describe("Optional holding period in years, may be fractional; when provided, the annualized (CAGR) return is also computed")
6017
+ },
6018
+ async ({ initialValue, finalValue, years }) => {
6019
+ const result = _calculateRoiMcp(initialValue, finalValue, years);
6020
+ if ("error" in result) return errText(result);
6021
+ return text(JSON.stringify(result, null, 2));
6022
+ }
6023
+ );
6024
+ var _MCP_EMOJI_TABLE = [
6025
+ { emoji: "\u{1F600}", name: "grinning face", shortcode: "grinning", codepoint: "U+1F600", category: "Smileys & Emotion", keywords: ["happy", "smile"] },
6026
+ { emoji: "\u{1F603}", name: "grinning face with big eyes", shortcode: "smiley", codepoint: "U+1F603", category: "Smileys & Emotion", keywords: ["happy", "joy"] },
6027
+ { emoji: "\u{1F604}", name: "grinning face with smiling eyes", shortcode: "smile", codepoint: "U+1F604", category: "Smileys & Emotion", keywords: ["happy", "joy"] },
6028
+ { emoji: "\u{1F601}", name: "beaming face with smiling eyes", shortcode: "grin", codepoint: "U+1F601", category: "Smileys & Emotion", keywords: ["happy", "teeth"] },
6029
+ { emoji: "\u{1F606}", name: "grinning squinting face", shortcode: "laughing", codepoint: "U+1F606", category: "Smileys & Emotion", keywords: ["laugh", "haha"] },
6030
+ { emoji: "\u{1F605}", name: "grinning face with sweat", shortcode: "sweat_smile", codepoint: "U+1F605", category: "Smileys & Emotion", keywords: ["nervous", "relief"] },
6031
+ { emoji: "\u{1F923}", name: "rolling on the floor laughing", shortcode: "rofl", codepoint: "U+1F923", category: "Smileys & Emotion", keywords: ["lol", "funny"] },
6032
+ { emoji: "\u{1F602}", name: "face with tears of joy", shortcode: "joy", codepoint: "U+1F602", category: "Smileys & Emotion", keywords: ["lol", "funny", "crying laughing"] },
6033
+ { emoji: "\u{1F642}", name: "slightly smiling face", shortcode: "slightly_smiling_face", codepoint: "U+1F642", category: "Smileys & Emotion", keywords: ["smile"] },
6034
+ { emoji: "\u{1F643}", name: "upside-down face", shortcode: "upside_down_face", codepoint: "U+1F643", category: "Smileys & Emotion", keywords: ["silly", "sarcasm"] },
6035
+ { emoji: "\u{1F609}", name: "winking face", shortcode: "wink", codepoint: "U+1F609", category: "Smileys & Emotion", keywords: ["flirt"] },
6036
+ { emoji: "\u{1F60A}", name: "smiling face with smiling eyes", shortcode: "blush", codepoint: "U+1F60A", category: "Smileys & Emotion", keywords: ["happy", "warm"] },
6037
+ { emoji: "\u{1F607}", name: "smiling face with halo", shortcode: "innocent", codepoint: "U+1F607", category: "Smileys & Emotion", keywords: ["angel"] },
6038
+ { emoji: "\u{1F970}", name: "smiling face with hearts", shortcode: "smiling_face_with_three_hearts", codepoint: "U+1F970", category: "Smileys & Emotion", keywords: ["love", "adore"] },
6039
+ { emoji: "\u{1F60D}", name: "smiling face with heart-eyes", shortcode: "heart_eyes", codepoint: "U+1F60D", category: "Smileys & Emotion", keywords: ["love", "crush"] },
6040
+ { emoji: "\u{1F929}", name: "star-struck", shortcode: "star_struck", codepoint: "U+1F929", category: "Smileys & Emotion", keywords: ["excited", "wow"] },
6041
+ { emoji: "\u{1F618}", name: "face blowing a kiss", shortcode: "kissing_heart", codepoint: "U+1F618", category: "Smileys & Emotion", keywords: ["kiss", "love"] },
6042
+ { emoji: "\u{1F617}", name: "kissing face", shortcode: "kissing", codepoint: "U+1F617", category: "Smileys & Emotion", keywords: ["kiss"] },
6043
+ { emoji: "\u{1F60B}", name: "face savoring food", shortcode: "yum", codepoint: "U+1F60B", category: "Smileys & Emotion", keywords: ["tasty", "delicious"] },
6044
+ { emoji: "\u{1F61B}", name: "face with tongue", shortcode: "stuck_out_tongue", codepoint: "U+1F61B", category: "Smileys & Emotion", keywords: ["playful"] },
6045
+ { emoji: "\u{1F61C}", name: "winking face with tongue", shortcode: "stuck_out_tongue_winking_eye", codepoint: "U+1F61C", category: "Smileys & Emotion", keywords: ["silly"] },
6046
+ { emoji: "\u{1F92A}", name: "zany face", shortcode: "zany_face", codepoint: "U+1F92A", category: "Smileys & Emotion", keywords: ["crazy", "wild"] },
6047
+ { emoji: "\u{1F61D}", name: "squinting face with tongue", shortcode: "stuck_out_tongue_closed_eyes", codepoint: "U+1F61D", category: "Smileys & Emotion", keywords: ["silly"] },
6048
+ { emoji: "\u{1F911}", name: "money-mouth face", shortcode: "money_mouth_face", codepoint: "U+1F911", category: "Smileys & Emotion", keywords: ["rich", "dollar"] },
6049
+ { emoji: "\u{1F917}", name: "smiling face with open hands", shortcode: "hugs", codepoint: "U+1F917", category: "Smileys & Emotion", keywords: ["hug"] },
6050
+ { emoji: "\u{1F92D}", name: "face with hand over mouth", shortcode: "hand_over_mouth", codepoint: "U+1F92D", category: "Smileys & Emotion", keywords: ["oops", "giggle"] },
6051
+ { emoji: "\u{1F92B}", name: "shushing face", shortcode: "shushing_face", codepoint: "U+1F92B", category: "Smileys & Emotion", keywords: ["quiet", "secret"] },
6052
+ { emoji: "\u{1F914}", name: "thinking face", shortcode: "thinking", codepoint: "U+1F914", category: "Smileys & Emotion", keywords: ["hmm", "consider"] },
6053
+ { emoji: "\u{1F910}", name: "zipper-mouth face", shortcode: "zipper_mouth_face", codepoint: "U+1F910", category: "Smileys & Emotion", keywords: ["secret", "silence"] },
6054
+ { emoji: "\u{1F928}", name: "face with raised eyebrow", shortcode: "raised_eyebrow", codepoint: "U+1F928", category: "Smileys & Emotion", keywords: ["skeptical", "suspicious"] },
6055
+ { emoji: "\u{1F610}", name: "neutral face", shortcode: "neutral_face", codepoint: "U+1F610", category: "Smileys & Emotion", keywords: ["meh"] },
6056
+ { emoji: "\u{1F611}", name: "expressionless face", shortcode: "expressionless", codepoint: "U+1F611", category: "Smileys & Emotion", keywords: ["blank"] },
6057
+ { emoji: "\u{1F636}", name: "face without mouth", shortcode: "no_mouth", codepoint: "U+1F636", category: "Smileys & Emotion", keywords: ["speechless"] },
6058
+ { emoji: "\u{1F60F}", name: "smirking face", shortcode: "smirk", codepoint: "U+1F60F", category: "Smileys & Emotion", keywords: ["smug"] },
6059
+ { emoji: "\u{1F612}", name: "unamused face", shortcode: "unamused", codepoint: "U+1F612", category: "Smileys & Emotion", keywords: ["annoyed"] },
6060
+ { emoji: "\u{1F644}", name: "face with rolling eyes", shortcode: "roll_eyes", codepoint: "U+1F644", category: "Smileys & Emotion", keywords: ["annoyed", "whatever"] },
6061
+ { emoji: "\u{1F62C}", name: "grimacing face", shortcode: "grimacing", codepoint: "U+1F62C", category: "Smileys & Emotion", keywords: ["awkward", "yikes"] },
6062
+ { emoji: "\u{1F60C}", name: "relieved face", shortcode: "relieved", codepoint: "U+1F60C", category: "Smileys & Emotion", keywords: ["calm", "content"] },
6063
+ { emoji: "\u{1F614}", name: "pensive face", shortcode: "pensive", codepoint: "U+1F614", category: "Smileys & Emotion", keywords: ["sad", "thoughtful"] },
6064
+ { emoji: "\u{1F62A}", name: "sleepy face", shortcode: "sleepy", codepoint: "U+1F62A", category: "Smileys & Emotion", keywords: ["tired"] },
6065
+ { emoji: "\u{1F924}", name: "drooling face", shortcode: "drooling_face", codepoint: "U+1F924", category: "Smileys & Emotion", keywords: ["hungry"] },
6066
+ { emoji: "\u{1F634}", name: "sleeping face", shortcode: "sleeping", codepoint: "U+1F634", category: "Smileys & Emotion", keywords: ["zzz", "asleep"] },
6067
+ { emoji: "\u{1F637}", name: "face with medical mask", shortcode: "mask", codepoint: "U+1F637", category: "Smileys & Emotion", keywords: ["sick", "ill"] },
6068
+ { emoji: "\u{1F912}", name: "face with thermometer", shortcode: "face_with_thermometer", codepoint: "U+1F912", category: "Smileys & Emotion", keywords: ["sick", "fever"] },
6069
+ { emoji: "\u{1F915}", name: "face with head-bandage", shortcode: "face_with_head_bandage", codepoint: "U+1F915", category: "Smileys & Emotion", keywords: ["hurt", "injured"] },
6070
+ { emoji: "\u{1F922}", name: "nauseated face", shortcode: "nauseated_face", codepoint: "U+1F922", category: "Smileys & Emotion", keywords: ["sick", "gross"] },
6071
+ { emoji: "\u{1F92E}", name: "face vomiting", shortcode: "vomiting_face", codepoint: "U+1F92E", category: "Smileys & Emotion", keywords: ["sick", "gross"] },
6072
+ { emoji: "\u{1F927}", name: "sneezing face", shortcode: "sneezing_face", codepoint: "U+1F927", category: "Smileys & Emotion", keywords: ["sick", "cold"] },
6073
+ { emoji: "\u{1F975}", name: "hot face", shortcode: "hot_face", codepoint: "U+1F975", category: "Smileys & Emotion", keywords: ["heat", "sweating"] },
6074
+ { emoji: "\u{1F976}", name: "cold face", shortcode: "cold_face", codepoint: "U+1F976", category: "Smileys & Emotion", keywords: ["freezing", "frozen"] },
6075
+ { emoji: "\u{1F635}", name: "knocked-out face", shortcode: "dizzy_face", codepoint: "U+1F635", category: "Smileys & Emotion", keywords: ["dizzy", "confused"] },
6076
+ { emoji: "\u{1F92F}", name: "exploding head", shortcode: "exploding_head", codepoint: "U+1F92F", category: "Smileys & Emotion", keywords: ["mind blown", "shocked"] },
6077
+ { emoji: "\u{1F973}", name: "partying face", shortcode: "partying_face", codepoint: "U+1F973", category: "Smileys & Emotion", keywords: ["celebrate", "party"] },
6078
+ { emoji: "\u{1F60E}", name: "smiling face with sunglasses", shortcode: "sunglasses", codepoint: "U+1F60E", category: "Smileys & Emotion", keywords: ["cool"] },
6079
+ { emoji: "\u{1F913}", name: "nerd face", shortcode: "nerd_face", codepoint: "U+1F913", category: "Smileys & Emotion", keywords: ["geek", "glasses"] },
6080
+ { emoji: "\u{1F9D0}", name: "face with monocle", shortcode: "monocle_face", codepoint: "U+1F9D0", category: "Smileys & Emotion", keywords: ["inspect", "curious"] },
6081
+ { emoji: "\u{1F615}", name: "confused face", shortcode: "confused", codepoint: "U+1F615", category: "Smileys & Emotion", keywords: ["puzzled"] },
6082
+ { emoji: "\u{1F61F}", name: "worried face", shortcode: "worried", codepoint: "U+1F61F", category: "Smileys & Emotion", keywords: ["concerned"] },
6083
+ { emoji: "\u{1F641}", name: "slightly frowning face", shortcode: "slightly_frowning_face", codepoint: "U+1F641", category: "Smileys & Emotion", keywords: ["sad"] },
6084
+ { emoji: "\u{1F62E}", name: "face with open mouth", shortcode: "open_mouth", codepoint: "U+1F62E", category: "Smileys & Emotion", keywords: ["surprised", "wow"] },
6085
+ { emoji: "\u{1F62F}", name: "hushed face", shortcode: "hushed", codepoint: "U+1F62F", category: "Smileys & Emotion", keywords: ["surprised"] },
6086
+ { emoji: "\u{1F632}", name: "astonished face", shortcode: "astonished", codepoint: "U+1F632", category: "Smileys & Emotion", keywords: ["shocked"] },
6087
+ { emoji: "\u{1F633}", name: "flushed face", shortcode: "flushed", codepoint: "U+1F633", category: "Smileys & Emotion", keywords: ["embarrassed", "blush"] },
6088
+ { emoji: "\u{1F97A}", name: "pleading face", shortcode: "pleading_face", codepoint: "U+1F97A", category: "Smileys & Emotion", keywords: ["puppy eyes", "begging"] },
6089
+ { emoji: "\u{1F626}", name: "frowning face with open mouth", shortcode: "frowning", codepoint: "U+1F626", category: "Smileys & Emotion", keywords: ["shocked"] },
6090
+ { emoji: "\u{1F627}", name: "anguished face", shortcode: "anguished", codepoint: "U+1F627", category: "Smileys & Emotion", keywords: ["distressed"] },
6091
+ { emoji: "\u{1F628}", name: "fearful face", shortcode: "fearful", codepoint: "U+1F628", category: "Smileys & Emotion", keywords: ["scared", "afraid"] },
6092
+ { emoji: "\u{1F630}", name: "anxious face with sweat", shortcode: "cold_sweat", codepoint: "U+1F630", category: "Smileys & Emotion", keywords: ["nervous"] },
6093
+ { emoji: "\u{1F625}", name: "sad but relieved face", shortcode: "disappointed_relieved", codepoint: "U+1F625", category: "Smileys & Emotion", keywords: ["sad"] },
6094
+ { emoji: "\u{1F622}", name: "crying face", shortcode: "cry", codepoint: "U+1F622", category: "Smileys & Emotion", keywords: ["sad", "tear"] },
6095
+ { emoji: "\u{1F62D}", name: "loudly crying face", shortcode: "sob", codepoint: "U+1F62D", category: "Smileys & Emotion", keywords: ["sad", "bawling"] },
6096
+ { emoji: "\u{1F631}", name: "face screaming in fear", shortcode: "scream", codepoint: "U+1F631", category: "Smileys & Emotion", keywords: ["shocked", "horror"] },
6097
+ { emoji: "\u{1F616}", name: "confounded face", shortcode: "confounded", codepoint: "U+1F616", category: "Smileys & Emotion", keywords: ["frustrated"] },
6098
+ { emoji: "\u{1F623}", name: "persevering face", shortcode: "persevere", codepoint: "U+1F623", category: "Smileys & Emotion", keywords: ["struggling"] },
6099
+ { emoji: "\u{1F61E}", name: "disappointed face", shortcode: "disappointed", codepoint: "U+1F61E", category: "Smileys & Emotion", keywords: ["sad", "let down"] },
6100
+ { emoji: "\u{1F613}", name: "downcast face with sweat", shortcode: "sweat", codepoint: "U+1F613", category: "Smileys & Emotion", keywords: ["tired", "stressed"] },
6101
+ { emoji: "\u{1F629}", name: "weary face", shortcode: "weary", codepoint: "U+1F629", category: "Smileys & Emotion", keywords: ["tired", "exhausted"] },
6102
+ { emoji: "\u{1F62B}", name: "tired face", shortcode: "tired_face", codepoint: "U+1F62B", category: "Smileys & Emotion", keywords: ["exhausted"] },
6103
+ { emoji: "\u{1F971}", name: "yawning face", shortcode: "yawning_face", codepoint: "U+1F971", category: "Smileys & Emotion", keywords: ["tired", "bored"] },
6104
+ { emoji: "\u{1F624}", name: "face with steam from nose", shortcode: "triumph", codepoint: "U+1F624", category: "Smileys & Emotion", keywords: ["angry", "proud"] },
6105
+ { emoji: "\u{1F621}", name: "pouting face", shortcode: "rage", codepoint: "U+1F621", category: "Smileys & Emotion", keywords: ["angry", "mad"] },
6106
+ { emoji: "\u{1F620}", name: "angry face", shortcode: "angry", codepoint: "U+1F620", category: "Smileys & Emotion", keywords: ["mad"] },
6107
+ { emoji: "\u{1F92C}", name: "face with symbols on mouth", shortcode: "cursing_face", codepoint: "U+1F92C", category: "Smileys & Emotion", keywords: ["swearing", "angry"] },
6108
+ { emoji: "\u{1F608}", name: "smiling face with horns", shortcode: "smiling_imp", codepoint: "U+1F608", category: "Smileys & Emotion", keywords: ["devil", "evil"] },
6109
+ { emoji: "\u{1F47F}", name: "angry face with horns", shortcode: "imp", codepoint: "U+1F47F", category: "Smileys & Emotion", keywords: ["devil"] },
6110
+ { emoji: "\u{1F480}", name: "skull", shortcode: "skull", codepoint: "U+1F480", category: "Smileys & Emotion", keywords: ["dead", "death"] },
6111
+ { emoji: "\u{1F921}", name: "clown face", shortcode: "clown_face", codepoint: "U+1F921", category: "Smileys & Emotion", keywords: ["joker"] },
6112
+ { emoji: "\u{1F47B}", name: "ghost", shortcode: "ghost", codepoint: "U+1F47B", category: "Smileys & Emotion", keywords: ["spooky", "halloween"] },
6113
+ { emoji: "\u{1F47D}", name: "alien", shortcode: "alien", codepoint: "U+1F47D", category: "Smileys & Emotion", keywords: ["ufo", "extraterrestrial"] },
6114
+ { emoji: "\u{1F916}", name: "robot", shortcode: "robot", codepoint: "U+1F916", category: "Smileys & Emotion", keywords: ["ai", "bot"] },
6115
+ { emoji: "\u{1F63A}", name: "grinning cat", shortcode: "smiley_cat", codepoint: "U+1F63A", category: "Smileys & Emotion", keywords: ["cat"] },
6116
+ { emoji: "\u{1F639}", name: "cat with tears of joy", shortcode: "joy_cat", codepoint: "U+1F639", category: "Smileys & Emotion", keywords: ["cat", "laugh"] },
6117
+ { emoji: "\u{1F63B}", name: "smiling cat with heart-eyes", shortcode: "heart_eyes_cat", codepoint: "U+1F63B", category: "Smileys & Emotion", keywords: ["cat", "love"] },
6118
+ { emoji: "\u{1F44D}", name: "thumbs up", shortcode: "thumbsup", codepoint: "U+1F44D", category: "People & Body", keywords: ["approve", "like", "yes"] },
6119
+ { emoji: "\u{1F44E}", name: "thumbs down", shortcode: "thumbsdown", codepoint: "U+1F44E", category: "People & Body", keywords: ["disapprove", "no"] },
6120
+ { emoji: "\u{1F44C}", name: "OK hand", shortcode: "ok_hand", codepoint: "U+1F44C", category: "People & Body", keywords: ["okay", "perfect"] },
6121
+ { emoji: "\u270C\uFE0F", name: "victory hand", shortcode: "v", codepoint: "U+270C U+FE0F", category: "People & Body", keywords: ["peace"] },
6122
+ { emoji: "\u{1F91E}", name: "crossed fingers", shortcode: "crossed_fingers", codepoint: "U+1F91E", category: "People & Body", keywords: ["luck", "hope"] },
6123
+ { emoji: "\u{1F918}", name: "sign of the horns", shortcode: "metal", codepoint: "U+1F918", category: "People & Body", keywords: ["rock"] },
6124
+ { emoji: "\u{1F44F}", name: "clapping hands", shortcode: "clap", codepoint: "U+1F44F", category: "People & Body", keywords: ["applause", "bravo"] },
6125
+ { emoji: "\u{1F64C}", name: "raising hands", shortcode: "raised_hands", codepoint: "U+1F64C", category: "People & Body", keywords: ["celebrate", "hooray"] },
6126
+ { emoji: "\u{1F450}", name: "open hands", shortcode: "open_hands", codepoint: "U+1F450", category: "People & Body", keywords: ["hug"] },
6127
+ { emoji: "\u{1F91D}", name: "handshake", shortcode: "handshake", codepoint: "U+1F91D", category: "People & Body", keywords: ["deal", "agreement"] },
6128
+ { emoji: "\u{1F64F}", name: "folded hands", shortcode: "pray", codepoint: "U+1F64F", category: "People & Body", keywords: ["please", "thanks", "praying"] },
6129
+ { emoji: "\u270D\uFE0F", name: "writing hand", shortcode: "writing_hand", codepoint: "U+270D U+FE0F", category: "People & Body", keywords: ["write"] },
6130
+ { emoji: "\u{1F4AA}", name: "flexed biceps", shortcode: "muscle", codepoint: "U+1F4AA", category: "People & Body", keywords: ["strong", "gym"] },
6131
+ { emoji: "\u{1F590}\uFE0F", name: "hand with fingers splayed", shortcode: "raised_hand_with_fingers_splayed", codepoint: "U+1F590 U+FE0F", category: "People & Body", keywords: ["stop"] },
6132
+ { emoji: "\u{1F44B}", name: "waving hand", shortcode: "wave", codepoint: "U+1F44B", category: "People & Body", keywords: ["hello", "goodbye", "bye"] },
6133
+ { emoji: "\u{1F440}", name: "eyes", shortcode: "eyes", codepoint: "U+1F440", category: "People & Body", keywords: ["look", "watching"] },
6134
+ { emoji: "\u{1F9E0}", name: "brain", shortcode: "brain", codepoint: "U+1F9E0", category: "People & Body", keywords: ["smart", "mind"] },
6135
+ { emoji: "\u2764\uFE0F", name: "red heart", shortcode: "heart", codepoint: "U+2764 U+FE0F", category: "Smileys & Emotion", keywords: ["love"] },
6136
+ { emoji: "\u{1F9E1}", name: "orange heart", shortcode: "orange_heart", codepoint: "U+1F9E1", category: "Smileys & Emotion", keywords: ["love"] },
6137
+ { emoji: "\u{1F49B}", name: "yellow heart", shortcode: "yellow_heart", codepoint: "U+1F49B", category: "Smileys & Emotion", keywords: ["love"] },
6138
+ { emoji: "\u{1F49A}", name: "green heart", shortcode: "green_heart", codepoint: "U+1F49A", category: "Smileys & Emotion", keywords: ["love"] },
6139
+ { emoji: "\u{1F499}", name: "blue heart", shortcode: "blue_heart", codepoint: "U+1F499", category: "Smileys & Emotion", keywords: ["love"] },
6140
+ { emoji: "\u{1F49C}", name: "purple heart", shortcode: "purple_heart", codepoint: "U+1F49C", category: "Smileys & Emotion", keywords: ["love"] },
6141
+ { emoji: "\u{1F5A4}", name: "black heart", shortcode: "black_heart", codepoint: "U+1F5A4", category: "Smileys & Emotion", keywords: ["love", "dark"] },
6142
+ { emoji: "\u{1F90D}", name: "white heart", shortcode: "white_heart", codepoint: "U+1F90D", category: "Smileys & Emotion", keywords: ["love"] },
6143
+ { emoji: "\u{1F494}", name: "broken heart", shortcode: "broken_heart", codepoint: "U+1F494", category: "Smileys & Emotion", keywords: ["heartbroken", "sad"] },
6144
+ { emoji: "\u{1F495}", name: "two hearts", shortcode: "two_hearts", codepoint: "U+1F495", category: "Smileys & Emotion", keywords: ["love"] },
6145
+ { emoji: "\u{1F496}", name: "sparkling heart", shortcode: "sparkling_heart", codepoint: "U+1F496", category: "Smileys & Emotion", keywords: ["love"] },
6146
+ { emoji: "\u{1F4AF}", name: "hundred points", shortcode: "100", codepoint: "U+1F4AF", category: "Smileys & Emotion", keywords: ["perfect", "score"] },
6147
+ { emoji: "\u{1F525}", name: "fire", shortcode: "fire", codepoint: "U+1F525", category: "Travel & Places", keywords: ["lit", "hot", "flame"] },
6148
+ { emoji: "\u2728", name: "sparkles", shortcode: "sparkles", codepoint: "U+2728", category: "Travel & Places", keywords: ["shiny", "glitter"] },
6149
+ { emoji: "\u2B50", name: "star", shortcode: "star", codepoint: "U+2B50", category: "Travel & Places", keywords: ["favorite"] },
6150
+ { emoji: "\u{1F31F}", name: "glowing star", shortcode: "star2", codepoint: "U+1F31F", category: "Travel & Places", keywords: ["shiny"] },
6151
+ { emoji: "\u{1F389}", name: "party popper", shortcode: "tada", codepoint: "U+1F389", category: "Activities", keywords: ["celebrate", "congrats"] },
6152
+ { emoji: "\u{1F38A}", name: "confetti ball", shortcode: "confetti_ball", codepoint: "U+1F38A", category: "Activities", keywords: ["celebrate"] },
6153
+ { emoji: "\u{1F381}", name: "wrapped gift", shortcode: "gift", codepoint: "U+1F381", category: "Activities", keywords: ["present", "birthday"] },
6154
+ { emoji: "\u{1F388}", name: "balloon", shortcode: "balloon", codepoint: "U+1F388", category: "Activities", keywords: ["party", "birthday"] },
6155
+ { emoji: "\u{1F3C6}", name: "trophy", shortcode: "trophy", codepoint: "U+1F3C6", category: "Activities", keywords: ["winner", "award"] },
6156
+ { emoji: "\u{1F947}", name: "1st place medal", shortcode: "first_place_medal", codepoint: "U+1F947", category: "Activities", keywords: ["gold", "winner"] },
6157
+ { emoji: "\u26BD", name: "soccer ball", shortcode: "soccer", codepoint: "U+26BD", category: "Activities", keywords: ["football"] },
6158
+ { emoji: "\u{1F3C0}", name: "basketball", shortcode: "basketball", codepoint: "U+1F3C0", category: "Activities", keywords: ["sport"] },
6159
+ { emoji: "\u{1F3C8}", name: "american football", shortcode: "football", codepoint: "U+1F3C8", category: "Activities", keywords: ["sport", "nfl"] },
6160
+ { emoji: "\u26BE", name: "baseball", shortcode: "baseball", codepoint: "U+26BE", category: "Activities", keywords: ["sport"] },
6161
+ { emoji: "\u{1F3BE}", name: "tennis", shortcode: "tennis", codepoint: "U+1F3BE", category: "Activities", keywords: ["sport"] },
6162
+ { emoji: "\u{1F3AE}", name: "video game", shortcode: "video_game", codepoint: "U+1F3AE", category: "Activities", keywords: ["gaming", "controller"] },
6163
+ { emoji: "\u{1F3B2}", name: "game die", shortcode: "game_die", codepoint: "U+1F3B2", category: "Activities", keywords: ["dice", "random"] },
6164
+ { emoji: "\u{1F3A7}", name: "headphone", shortcode: "headphones", codepoint: "U+1F3A7", category: "Objects", keywords: ["music", "audio"] },
6165
+ { emoji: "\u{1F3B5}", name: "musical note", shortcode: "musical_note", codepoint: "U+1F3B5", category: "Objects", keywords: ["music"] },
6166
+ { emoji: "\u{1F3B6}", name: "musical notes", shortcode: "notes", codepoint: "U+1F3B6", category: "Objects", keywords: ["music"] },
6167
+ { emoji: "\u{1F436}", name: "dog face", shortcode: "dog", codepoint: "U+1F436", category: "Animals & Nature", keywords: ["puppy", "pet"] },
6168
+ { emoji: "\u{1F431}", name: "cat face", shortcode: "cat", codepoint: "U+1F431", category: "Animals & Nature", keywords: ["kitten", "pet"] },
6169
+ { emoji: "\u{1F42D}", name: "mouse face", shortcode: "mouse", codepoint: "U+1F42D", category: "Animals & Nature", keywords: ["rodent"] },
6170
+ { emoji: "\u{1F439}", name: "hamster face", shortcode: "hamster", codepoint: "U+1F439", category: "Animals & Nature", keywords: ["pet"] },
6171
+ { emoji: "\u{1F430}", name: "rabbit face", shortcode: "rabbit", codepoint: "U+1F430", category: "Animals & Nature", keywords: ["bunny"] },
6172
+ { emoji: "\u{1F98A}", name: "fox", shortcode: "fox_face", codepoint: "U+1F98A", category: "Animals & Nature", keywords: ["animal"] },
6173
+ { emoji: "\u{1F43B}", name: "bear", shortcode: "bear", codepoint: "U+1F43B", category: "Animals & Nature", keywords: ["animal"] },
6174
+ { emoji: "\u{1F43C}", name: "panda", shortcode: "panda_face", codepoint: "U+1F43C", category: "Animals & Nature", keywords: ["animal"] },
6175
+ { emoji: "\u{1F428}", name: "koala", shortcode: "koala", codepoint: "U+1F428", category: "Animals & Nature", keywords: ["animal"] },
6176
+ { emoji: "\u{1F42F}", name: "tiger face", shortcode: "tiger", codepoint: "U+1F42F", category: "Animals & Nature", keywords: ["animal"] },
6177
+ { emoji: "\u{1F981}", name: "lion", shortcode: "lion", codepoint: "U+1F981", category: "Animals & Nature", keywords: ["animal"] },
6178
+ { emoji: "\u{1F42E}", name: "cow face", shortcode: "cow", codepoint: "U+1F42E", category: "Animals & Nature", keywords: ["animal"] },
6179
+ { emoji: "\u{1F437}", name: "pig face", shortcode: "pig", codepoint: "U+1F437", category: "Animals & Nature", keywords: ["animal"] },
6180
+ { emoji: "\u{1F438}", name: "frog", shortcode: "frog", codepoint: "U+1F438", category: "Animals & Nature", keywords: ["animal"] },
6181
+ { emoji: "\u{1F435}", name: "monkey face", shortcode: "monkey_face", codepoint: "U+1F435", category: "Animals & Nature", keywords: ["animal"] },
6182
+ { emoji: "\u{1F414}", name: "chicken", shortcode: "chicken", codepoint: "U+1F414", category: "Animals & Nature", keywords: ["animal", "bird"] },
6183
+ { emoji: "\u{1F427}", name: "penguin", shortcode: "penguin", codepoint: "U+1F427", category: "Animals & Nature", keywords: ["animal", "bird"] },
6184
+ { emoji: "\u{1F426}", name: "bird", shortcode: "bird", codepoint: "U+1F426", category: "Animals & Nature", keywords: ["animal"] },
6185
+ { emoji: "\u{1F984}", name: "unicorn", shortcode: "unicorn", codepoint: "U+1F984", category: "Animals & Nature", keywords: ["fantasy"] },
6186
+ { emoji: "\u{1F41D}", name: "honeybee", shortcode: "bee", codepoint: "U+1F41D", category: "Animals & Nature", keywords: ["insect"] },
6187
+ { emoji: "\u{1F98B}", name: "butterfly", shortcode: "butterfly", codepoint: "U+1F98B", category: "Animals & Nature", keywords: ["insect"] },
6188
+ { emoji: "\u{1F422}", name: "turtle", shortcode: "turtle", codepoint: "U+1F422", category: "Animals & Nature", keywords: ["animal", "slow"] },
6189
+ { emoji: "\u{1F40D}", name: "snake", shortcode: "snake", codepoint: "U+1F40D", category: "Animals & Nature", keywords: ["animal"] },
6190
+ { emoji: "\u{1F433}", name: "spouting whale", shortcode: "whale", codepoint: "U+1F433", category: "Animals & Nature", keywords: ["ocean"] },
6191
+ { emoji: "\u{1F42C}", name: "dolphin", shortcode: "dolphin", codepoint: "U+1F42C", category: "Animals & Nature", keywords: ["ocean"] },
6192
+ { emoji: "\u{1F41F}", name: "fish", shortcode: "fish", codepoint: "U+1F41F", category: "Animals & Nature", keywords: ["ocean"] },
6193
+ { emoji: "\u{1F338}", name: "cherry blossom", shortcode: "cherry_blossom", codepoint: "U+1F338", category: "Animals & Nature", keywords: ["flower", "spring"] },
6194
+ { emoji: "\u{1F339}", name: "rose", shortcode: "rose", codepoint: "U+1F339", category: "Animals & Nature", keywords: ["flower"] },
6195
+ { emoji: "\u{1F33B}", name: "sunflower", shortcode: "sunflower", codepoint: "U+1F33B", category: "Animals & Nature", keywords: ["flower"] },
6196
+ { emoji: "\u{1F308}", name: "rainbow", shortcode: "rainbow", codepoint: "U+1F308", category: "Travel & Places", keywords: ["colorful", "pride"] },
6197
+ { emoji: "\u2600\uFE0F", name: "sun", shortcode: "sunny", codepoint: "U+2600 U+FE0F", category: "Travel & Places", keywords: ["sunshine", "weather"] },
6198
+ { emoji: "\u26C5", name: "sun behind cloud", shortcode: "partly_sunny", codepoint: "U+26C5", category: "Travel & Places", keywords: ["weather"] },
6199
+ { emoji: "\u2601\uFE0F", name: "cloud", shortcode: "cloud", codepoint: "U+2601 U+FE0F", category: "Travel & Places", keywords: ["weather"] },
6200
+ { emoji: "\u{1F327}\uFE0F", name: "cloud with rain", shortcode: "cloud_with_rain", codepoint: "U+1F327 U+FE0F", category: "Travel & Places", keywords: ["weather", "rain"] },
6201
+ { emoji: "\u26C8\uFE0F", name: "cloud with lightning and rain", shortcode: "thunder_cloud_and_rain", codepoint: "U+26C8 U+FE0F", category: "Travel & Places", keywords: ["storm"] },
6202
+ { emoji: "\u2744\uFE0F", name: "snowflake", shortcode: "snowflake", codepoint: "U+2744 U+FE0F", category: "Travel & Places", keywords: ["cold", "winter"] },
6203
+ { emoji: "\u26C4", name: "snowman without snow", shortcode: "snowman_without_snow", codepoint: "U+26C4", category: "Travel & Places", keywords: ["winter"] },
6204
+ { emoji: "\u{1F30A}", name: "water wave", shortcode: "ocean", codepoint: "U+1F30A", category: "Travel & Places", keywords: ["sea", "surf"] },
6205
+ { emoji: "\u{1F34E}", name: "red apple", shortcode: "apple", codepoint: "U+1F34E", category: "Food & Drink", keywords: ["fruit"] },
6206
+ { emoji: "\u{1F34C}", name: "banana", shortcode: "banana", codepoint: "U+1F34C", category: "Food & Drink", keywords: ["fruit"] },
6207
+ { emoji: "\u{1F355}", name: "pizza", shortcode: "pizza", codepoint: "U+1F355", category: "Food & Drink", keywords: ["food"] },
6208
+ { emoji: "\u{1F354}", name: "hamburger", shortcode: "hamburger", codepoint: "U+1F354", category: "Food & Drink", keywords: ["burger", "food"] },
6209
+ { emoji: "\u{1F35F}", name: "french fries", shortcode: "fries", codepoint: "U+1F35F", category: "Food & Drink", keywords: ["food"] },
6210
+ { emoji: "\u{1F32E}", name: "taco", shortcode: "taco", codepoint: "U+1F32E", category: "Food & Drink", keywords: ["food"] },
6211
+ { emoji: "\u{1F363}", name: "sushi", shortcode: "sushi", codepoint: "U+1F363", category: "Food & Drink", keywords: ["food"] },
6212
+ { emoji: "\u{1F369}", name: "doughnut", shortcode: "doughnut", codepoint: "U+1F369", category: "Food & Drink", keywords: ["donut", "food"] },
6213
+ { emoji: "\u{1F36A}", name: "cookie", shortcode: "cookie", codepoint: "U+1F36A", category: "Food & Drink", keywords: ["food"] },
6214
+ { emoji: "\u{1F382}", name: "birthday cake", shortcode: "birthday", codepoint: "U+1F382", category: "Food & Drink", keywords: ["cake", "party"] },
6215
+ { emoji: "\u{1F370}", name: "shortcake", shortcode: "cake", codepoint: "U+1F370", category: "Food & Drink", keywords: ["dessert"] },
6216
+ { emoji: "\u{1F36B}", name: "chocolate bar", shortcode: "chocolate_bar", codepoint: "U+1F36B", category: "Food & Drink", keywords: ["candy", "sweet"] },
6217
+ { emoji: "\u{1F37F}", name: "popcorn", shortcode: "popcorn", codepoint: "U+1F37F", category: "Food & Drink", keywords: ["movie", "snack"] },
6218
+ { emoji: "\u2615", name: "hot beverage", shortcode: "coffee", codepoint: "U+2615", category: "Food & Drink", keywords: ["tea", "drink"] },
6219
+ { emoji: "\u{1F37A}", name: "beer mug", shortcode: "beer", codepoint: "U+1F37A", category: "Food & Drink", keywords: ["drink", "alcohol"] },
6220
+ { emoji: "\u{1F377}", name: "wine glass", shortcode: "wine_glass", codepoint: "U+1F377", category: "Food & Drink", keywords: ["drink", "alcohol"] },
6221
+ { emoji: "\u{1F37E}", name: "bottle with popping cork", shortcode: "champagne", codepoint: "U+1F37E", category: "Food & Drink", keywords: ["celebrate", "drink"] },
6222
+ { emoji: "\u{1F680}", name: "rocket", shortcode: "rocket", codepoint: "U+1F680", category: "Travel & Places", keywords: ["launch", "space", "ship"] },
6223
+ { emoji: "\u2708\uFE0F", name: "airplane", shortcode: "airplane", codepoint: "U+2708 U+FE0F", category: "Travel & Places", keywords: ["flight", "travel"] },
6224
+ { emoji: "\u{1F697}", name: "automobile", shortcode: "car", codepoint: "U+1F697", category: "Travel & Places", keywords: ["vehicle"] },
6225
+ { emoji: "\u{1F6B2}", name: "bicycle", shortcode: "bike", codepoint: "U+1F6B2", category: "Travel & Places", keywords: ["cycling"] },
6226
+ { emoji: "\u{1F6A2}", name: "ship", shortcode: "ship", codepoint: "U+1F6A2", category: "Travel & Places", keywords: ["boat"] },
6227
+ { emoji: "\u{1F3E0}", name: "house", shortcode: "house", codepoint: "U+1F3E0", category: "Travel & Places", keywords: ["home"] },
6228
+ { emoji: "\u{1F3E2}", name: "office building", shortcode: "office", codepoint: "U+1F3E2", category: "Travel & Places", keywords: ["work"] },
6229
+ { emoji: "\u{1F30D}", name: "globe showing Europe-Africa", shortcode: "earth_africa", codepoint: "U+1F30D", category: "Travel & Places", keywords: ["world", "global"] },
6230
+ { emoji: "\u{1F5FA}\uFE0F", name: "world map", shortcode: "world_map", codepoint: "U+1F5FA U+FE0F", category: "Travel & Places", keywords: ["travel"] },
6231
+ { emoji: "\u{1F319}", name: "crescent moon", shortcode: "crescent_moon", codepoint: "U+1F319", category: "Travel & Places", keywords: ["night"] },
6232
+ { emoji: "\u{1F4BB}", name: "laptop", shortcode: "computer", codepoint: "U+1F4BB", category: "Objects", keywords: ["dev", "code"] },
6233
+ { emoji: "\u{1F5A5}\uFE0F", name: "desktop computer", shortcode: "desktop_computer", codepoint: "U+1F5A5 U+FE0F", category: "Objects", keywords: ["dev"] },
6234
+ { emoji: "\u2328\uFE0F", name: "keyboard", shortcode: "keyboard", codepoint: "U+2328 U+FE0F", category: "Objects", keywords: ["type", "dev"] },
6235
+ { emoji: "\u{1F5B1}\uFE0F", name: "computer mouse", shortcode: "computer_mouse", codepoint: "U+1F5B1 U+FE0F", category: "Objects", keywords: ["dev"] },
6236
+ { emoji: "\u{1F4F1}", name: "mobile phone", shortcode: "iphone", codepoint: "U+1F4F1", category: "Objects", keywords: ["phone"] },
6237
+ { emoji: "\u260E\uFE0F", name: "telephone", shortcode: "telephone", codepoint: "U+260E U+FE0F", category: "Objects", keywords: ["phone"] },
6238
+ { emoji: "\u{1F4A1}", name: "light bulb", shortcode: "bulb", codepoint: "U+1F4A1", category: "Objects", keywords: ["idea"] },
6239
+ { emoji: "\u{1F50B}", name: "battery", shortcode: "battery", codepoint: "U+1F50B", category: "Objects", keywords: ["power"] },
6240
+ { emoji: "\u{1F50C}", name: "electric plug", shortcode: "electric_plug", codepoint: "U+1F50C", category: "Objects", keywords: ["power"] },
6241
+ { emoji: "\u{1F4F7}", name: "camera", shortcode: "camera", codepoint: "U+1F4F7", category: "Objects", keywords: ["photo"] },
6242
+ { emoji: "\u{1F4DA}", name: "books", shortcode: "books", codepoint: "U+1F4DA", category: "Objects", keywords: ["read", "study"] },
6243
+ { emoji: "\u{1F4D6}", name: "open book", shortcode: "book", codepoint: "U+1F4D6", category: "Objects", keywords: ["read"] },
6244
+ { emoji: "\u{1F4DD}", name: "memo", shortcode: "memo", codepoint: "U+1F4DD", category: "Objects", keywords: ["note", "write"] },
6245
+ { emoji: "\u270F\uFE0F", name: "pencil", shortcode: "pencil2", codepoint: "U+270F U+FE0F", category: "Objects", keywords: ["write"] },
6246
+ { emoji: "\u{1F58A}\uFE0F", name: "pen", shortcode: "pen", codepoint: "U+1F58A U+FE0F", category: "Objects", keywords: ["write"] },
6247
+ { emoji: "\u{1F4CC}", name: "pushpin", shortcode: "pushpin", codepoint: "U+1F4CC", category: "Objects", keywords: ["pin"] },
6248
+ { emoji: "\u{1F4CE}", name: "paperclip", shortcode: "paperclip", codepoint: "U+1F4CE", category: "Objects", keywords: ["attach"] },
6249
+ { emoji: "\u{1F517}", name: "link", shortcode: "link", codepoint: "U+1F517", category: "Objects", keywords: ["url", "chain"] },
6250
+ { emoji: "\u{1F512}", name: "locked", shortcode: "lock", codepoint: "U+1F512", category: "Objects", keywords: ["secure", "private"] },
6251
+ { emoji: "\u{1F513}", name: "unlocked", shortcode: "unlock", codepoint: "U+1F513", category: "Objects", keywords: ["open"] },
6252
+ { emoji: "\u{1F511}", name: "key", shortcode: "key", codepoint: "U+1F511", category: "Objects", keywords: ["password"] },
6253
+ { emoji: "\u{1F50D}", name: "magnifying glass tilted left", shortcode: "mag", codepoint: "U+1F50D", category: "Objects", keywords: ["search", "find"] },
6254
+ { emoji: "\u2699\uFE0F", name: "gear", shortcode: "gear", codepoint: "U+2699 U+FE0F", category: "Objects", keywords: ["settings", "config"] },
6255
+ { emoji: "\u{1F6E0}\uFE0F", name: "hammer and wrench", shortcode: "hammer_and_wrench", codepoint: "U+1F6E0 U+FE0F", category: "Objects", keywords: ["tools", "build"] },
6256
+ { emoji: "\u{1F41B}", name: "bug", shortcode: "bug", codepoint: "U+1F41B", category: "Animals & Nature", keywords: ["insect", "error", "debug"] },
6257
+ { emoji: "\u{1F4B0}", name: "money bag", shortcode: "moneybag", codepoint: "U+1F4B0", category: "Objects", keywords: ["cash", "rich"] },
6258
+ { emoji: "\u{1F4B5}", name: "dollar banknote", shortcode: "dollar", codepoint: "U+1F4B5", category: "Objects", keywords: ["money", "cash"] },
6259
+ { emoji: "\u{1F4B3}", name: "credit card", shortcode: "credit_card", codepoint: "U+1F4B3", category: "Objects", keywords: ["payment"] },
6260
+ { emoji: "\u{1F4C8}", name: "chart increasing", shortcode: "chart_with_upwards_trend", codepoint: "U+1F4C8", category: "Objects", keywords: ["growth", "stocks"] },
6261
+ { emoji: "\u{1F4C9}", name: "chart decreasing", shortcode: "chart_with_downwards_trend", codepoint: "U+1F4C9", category: "Objects", keywords: ["decline", "stocks"] },
6262
+ { emoji: "\u{1F4CA}", name: "bar chart", shortcode: "bar_chart", codepoint: "U+1F4CA", category: "Objects", keywords: ["data", "stats"] },
6263
+ { emoji: "\u{1F4C5}", name: "calendar", shortcode: "date", codepoint: "U+1F4C5", category: "Objects", keywords: ["schedule"] },
6264
+ { emoji: "\u23F0", name: "alarm clock", shortcode: "alarm_clock", codepoint: "U+23F0", category: "Objects", keywords: ["time", "wake"] },
6265
+ { emoji: "\u23F3", name: "hourglass not done", shortcode: "hourglass_flowing_sand", codepoint: "U+23F3", category: "Objects", keywords: ["waiting", "time"] },
6266
+ { emoji: "\u2705", name: "check mark button", shortcode: "white_check_mark", codepoint: "U+2705", category: "Symbols", keywords: ["done", "correct", "yes"] },
6267
+ { emoji: "\u2714\uFE0F", name: "check mark", shortcode: "heavy_check_mark", codepoint: "U+2714 U+FE0F", category: "Symbols", keywords: ["done", "correct"] },
6268
+ { emoji: "\u274C", name: "cross mark", shortcode: "x", codepoint: "U+274C", category: "Symbols", keywords: ["wrong", "no", "error"] },
6269
+ { emoji: "\u2757", name: "exclamation mark", shortcode: "exclamation", codepoint: "U+2757", category: "Symbols", keywords: ["warning", "important"] },
6270
+ { emoji: "\u2753", name: "question mark", shortcode: "question", codepoint: "U+2753", category: "Symbols", keywords: ["ask"] },
6271
+ { emoji: "\u26A0\uFE0F", name: "warning", shortcode: "warning", codepoint: "U+26A0 U+FE0F", category: "Symbols", keywords: ["caution", "alert"] },
6272
+ { emoji: "\u{1F6AB}", name: "prohibited", shortcode: "no_entry_sign", codepoint: "U+1F6AB", category: "Symbols", keywords: ["forbidden", "banned"] },
6273
+ { emoji: "\u{1F534}", name: "red circle", shortcode: "red_circle", codepoint: "U+1F534", category: "Symbols", keywords: ["status", "stop"] },
6274
+ { emoji: "\u{1F7E2}", name: "green circle", shortcode: "green_circle", codepoint: "U+1F7E2", category: "Symbols", keywords: ["status", "go"] },
6275
+ { emoji: "\u{1F7E1}", name: "yellow circle", shortcode: "yellow_circle", codepoint: "U+1F7E1", category: "Symbols", keywords: ["status", "warning"] },
6276
+ { emoji: "\u{1F535}", name: "blue circle", shortcode: "blue_circle", codepoint: "U+1F535", category: "Symbols", keywords: ["status"] },
6277
+ { emoji: "\u2B06\uFE0F", name: "up arrow", shortcode: "arrow_up", codepoint: "U+2B06 U+FE0F", category: "Symbols", keywords: ["direction"] },
6278
+ { emoji: "\u2B07\uFE0F", name: "down arrow", shortcode: "arrow_down", codepoint: "U+2B07 U+FE0F", category: "Symbols", keywords: ["direction"] },
6279
+ { emoji: "\u27A1\uFE0F", name: "right arrow", shortcode: "arrow_right", codepoint: "U+27A1 U+FE0F", category: "Symbols", keywords: ["direction"] },
6280
+ { emoji: "\u2B05\uFE0F", name: "left arrow", shortcode: "arrow_left", codepoint: "U+2B05 U+FE0F", category: "Symbols", keywords: ["direction"] },
6281
+ { emoji: "\u{1F504}", name: "counterclockwise arrows button", shortcode: "arrows_counterclockwise", codepoint: "U+1F504", category: "Symbols", keywords: ["refresh", "reload", "sync"] },
6282
+ { emoji: "\u267B\uFE0F", name: "recycling symbol", shortcode: "recycle", codepoint: "U+267B U+FE0F", category: "Symbols", keywords: ["reuse", "green"] },
6283
+ { emoji: "\u{1F195}", name: "NEW button", shortcode: "new", codepoint: "U+1F195", category: "Symbols", keywords: ["fresh"] },
6284
+ { emoji: "\u{1F193}", name: "FREE button", shortcode: "free", codepoint: "U+1F193", category: "Symbols", keywords: ["gratis"] },
6285
+ { emoji: "\u{1F4A4}", name: "zzz", shortcode: "zzz", codepoint: "U+1F4A4", category: "Symbols", keywords: ["sleep", "tired"] },
6286
+ { emoji: "\u{1F4AC}", name: "speech balloon", shortcode: "speech_balloon", codepoint: "U+1F4AC", category: "Objects", keywords: ["chat", "talk"] },
6287
+ { emoji: "\u{1F4AD}", name: "thought balloon", shortcode: "thought_balloon", codepoint: "U+1F4AD", category: "Objects", keywords: ["think"] },
6288
+ { emoji: "\u{1F5E3}\uFE0F", name: "speaking head", shortcode: "speaking_head", codepoint: "U+1F5E3 U+FE0F", category: "People & Body", keywords: ["talk"] },
6289
+ { emoji: "\u{1F3AF}", name: "direct hit", shortcode: "dart", codepoint: "U+1F3AF", category: "Activities", keywords: ["target", "goal"] },
6290
+ { emoji: "\u{1F6A9}", name: "triangular flag", shortcode: "triangular_flag_on_post", codepoint: "U+1F6A9", category: "Flags", keywords: ["flag", "report"] },
6291
+ { emoji: "\u{1F3C1}", name: "chequered flag", shortcode: "checkered_flag", codepoint: "U+1F3C1", category: "Flags", keywords: ["finish", "race"] },
6292
+ { emoji: "\u{1F1FA}\u{1F1F8}", name: "flag: United States", shortcode: "us", codepoint: "U+1F1FA U+1F1F8", category: "Flags", keywords: ["usa", "america"] },
6293
+ { emoji: "\u{1F1EC}\u{1F1E7}", name: "flag: United Kingdom", shortcode: "gb", codepoint: "U+1F1EC U+1F1E7", category: "Flags", keywords: ["uk", "britain"] },
6294
+ { emoji: "\u{1F1EE}\u{1F1F3}", name: "flag: India", shortcode: "in", codepoint: "U+1F1EE U+1F1F3", category: "Flags", keywords: ["india"] },
6295
+ { emoji: "\u{1F1EF}\u{1F1F5}", name: "flag: Japan", shortcode: "jp", codepoint: "U+1F1EF U+1F1F5", category: "Flags", keywords: ["japan"] },
6296
+ { emoji: "\u{1F1E9}\u{1F1EA}", name: "flag: Germany", shortcode: "de", codepoint: "U+1F1E9 U+1F1EA", category: "Flags", keywords: ["germany"] },
6297
+ { emoji: "\u{1F1EB}\u{1F1F7}", name: "flag: France", shortcode: "fr", codepoint: "U+1F1EB U+1F1F7", category: "Flags", keywords: ["france"] },
6298
+ { emoji: "\u{1F1E8}\u{1F1E6}", name: "flag: Canada", shortcode: "ca", codepoint: "U+1F1E8 U+1F1E6", category: "Flags", keywords: ["canada"] },
6299
+ { emoji: "\u{1F1E6}\u{1F1FA}", name: "flag: Australia", shortcode: "au", codepoint: "U+1F1E6 U+1F1FA", category: "Flags", keywords: ["australia"] },
6300
+ { emoji: "\u{1F1E7}\u{1F1F7}", name: "flag: Brazil", shortcode: "br", codepoint: "U+1F1E7 U+1F1F7", category: "Flags", keywords: ["brazil"] },
6301
+ { emoji: "\u{1F1E8}\u{1F1F3}", name: "flag: China", shortcode: "cn", codepoint: "U+1F1E8 U+1F1F3", category: "Flags", keywords: ["china"] }
6302
+ ];
6303
+ function _lookupEmojiMcp(query, mode) {
6304
+ if (!query || !query.trim()) return { error: "query is required" };
6305
+ const trimmed = query.trim();
6306
+ if (mode === "shortcode") {
6307
+ const s = trimmed.toLowerCase().replace(/^:|:$/g, "");
6308
+ const match = _MCP_EMOJI_TABLE.find((e) => e.shortcode.toLowerCase() === s);
6309
+ if (!match) return { error: `No emoji found for shortcode "${trimmed}"` };
6310
+ return { query: trimmed, mode, results: [match] };
6311
+ }
6312
+ if (mode === "char") {
6313
+ const match = _MCP_EMOJI_TABLE.find((e) => e.emoji === trimmed);
6314
+ if (!match) return { error: `No emoji entry found for character "${trimmed}"` };
6315
+ return { query: trimmed, mode, results: [match] };
6316
+ }
6317
+ if (mode === "category") {
6318
+ const c = trimmed.toLowerCase();
6319
+ const results2 = _MCP_EMOJI_TABLE.filter((e) => e.category.toLowerCase() === c);
6320
+ if (results2.length === 0) return { error: `No emoji found in category "${trimmed}"` };
6321
+ return { query: trimmed, mode, results: results2 };
6322
+ }
6323
+ const q = trimmed.toLowerCase().replace(/^:|:$/g, "");
6324
+ const results = _MCP_EMOJI_TABLE.filter(
6325
+ (e) => e.name.toLowerCase().includes(q) || e.shortcode.toLowerCase().includes(q) || e.keywords.some((k) => k.toLowerCase().includes(q))
6326
+ );
6327
+ return { query: trimmed, mode: "search", results };
6328
+ }
6329
+ server.tool(
6330
+ "lookup_emoji",
6331
+ 'Search a curated table of several hundred common emoji by name, GitHub-style shortcode, or keyword (mode "search", the default), or look one up exactly by shortcode, character, or category (modes "shortcode", "char", "category"). Not the full 3,000+ Unicode emoji set.',
6332
+ {
6333
+ query: z.string().describe("The search text, exact shortcode, exact emoji character, or category name, depending on mode"),
6334
+ mode: z.enum(["search", "shortcode", "char", "category"]).optional().describe('Lookup mode; defaults to "search"')
6335
+ },
6336
+ async ({ query, mode }) => {
6337
+ const result = _lookupEmojiMcp(query, mode ?? "search");
6338
+ if ("error" in result) return errText(result);
6339
+ return text(JSON.stringify(result, null, 2));
6340
+ }
6341
+ );
5854
6342
  var transport = new StdioServerTransport();
5855
6343
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilix-tech/mcp",
3
- "version": "0.34.0",
3
+ "version": "0.36.0",
4
4
  "description": "MCP server exposing 152 Utilix developer tools to Claude, Cursor, VS Code Copilot, and any MCP-compatible AI assistant.",
5
5
  "author": "Utilix <hello@utilix.tech>",
6
6
  "license": "MIT",