fix: changed truncation length for MCP tools and projects#8494
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThe changes adjust the maximum allowed length for generated server and tool names throughout both backend and frontend components, increasing their limits. Additionally, new logic is introduced to ensure tool names are unique by appending numeric suffixes if necessary. No public API signatures are altered, and the updates are internal to helper functions and UI logic. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend
participant Backend
User->>Frontend: Submit MCP server/tool name
Frontend->>Frontend: Truncate and sanitize name (30 chars)
Frontend->>Backend: Send name for registration/listing
Backend->>Backend: Truncate name (30 chars)
Backend->>Backend: Check for uniqueness, append suffix if needed
Backend->>Frontend: Return unique name/confirmation
Suggested labels
Suggested reviewers
✨ Finishing Touches🧪 Generate Unit Tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx (1)
182-188:⚠️ Potential issueTruncation length (25) does not match backend (26) – server detection will fail
lf-${…}.slice(0, 25)generates the key stored in the client config, but the backend now looks for a 26-char prefix ([:26]in mcp_projects.py).
As a result,check_installed_mcp_serverswill never find the entry and the UI will falsely report the server as “not installed”.- "lf-${parseString(folderName ?? "project", ["snake_case", "no_blank", "lowercase"]).slice(0, 25)}": { + "lf-${parseString(folderName ?? "project", ["snake_case", "no_blank", "lowercase"]).slice(0, 26)}": {Better yet, import a shared constant to avoid future drift.
🧹 Nitpick comments (4)
src/frontend/src/utils/mcpUtils.ts (1)
155-161: Avoid magic numbers – introduce a sharedMAX_SERVER_NAME_LENGTHconstant
name.slice(0, 30)hard-codes the truncation limit.
The same limit is scattered across several files (30 here, 25 in McpServerTab.tsx, 26 in the backend, etc.). Divergence is already creeping in.Create one authoritative constant (e.g.,
MAX_SERVER_NAME_LENGTH = 30) in a shared module (or.env) and reference it everywhere. This guarantees the front- and back-end stay in sync and prevents subtle bugs when any side changes the limit again.src/frontend/src/modals/addMcpServerModal/index.tsx (1)
133-139: Three identicalslice(0, 30)occurrences – DRY it upThe same truncation logic appears for STDIO, SSE and JSON branches. Repetition invites inconsistency.
Suggested approach:
- Add at top of file (or shared util):
export const MAX_SERVER_NAME_LENGTH = 30;
- Replace every
.slice(0, 30)with.slice(0, MAX_SERVER_NAME_LENGTH).This keeps the modal aligned with other components and makes future changes trivial.
Also applies to: 167-173, 199-207
src/backend/base/langflow/api/v1/mcp.py (1)
183-201: Good uniqueness logic – consider extractingMAX_TOOL_NAME_LENGTHThe new duplicate-aware block looks solid and handles suffix overflow correctly.
Minor improvement: pullmax_length = 30up to a module-level constant shared withmcp_projects.pyto avoid silent divergence.src/backend/base/langflow/api/v1/mcp_projects.py (1)
520-541: Duplicate-name resolver looks good – factor out limitSame comment as in mcp.py: promote
max_length = 30to a shared constant.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/backend/base/langflow/api/v1/mcp.py(1 hunks)src/backend/base/langflow/api/v1/mcp_projects.py(4 hunks)src/frontend/src/modals/addMcpServerModal/index.tsx(3 hunks)src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx(1 hunks)src/frontend/src/utils/mcpUtils.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx (1)
src/frontend/src/utils/stringManipulation.ts (1)
parseString(75-137)
src/backend/base/langflow/api/v1/mcp.py (1)
src/backend/base/langflow/helpers/flow.py (1)
json_schema_from_flow(319-359)
src/backend/base/langflow/api/v1/mcp_projects.py (1)
src/backend/tests/conftest.py (1)
flow(516-532)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Optimize new Python code in this PR
- GitHub Check: Ruff Style Check (3.13)
🔇 Additional comments (1)
src/backend/base/langflow/api/v1/mcp.py (1)
211-214:base_namein log message may be undefinedIf an exception occurs before
base_nameis set (e.g., duringjson_schema_from_flow), the except block still hasbase_namein scope, so it’s safe.
LGTM.
| # Create the MCP configuration | ||
| mcp_config = { | ||
| "mcpServers": {f"lf-{project.name.lower().replace(' ', '_')[:11]}": {"command": command, "args": args}} | ||
| "mcpServers": {f"lf-{project.name.lower().replace(' ', '_')[:26]}": {"command": command, "args": args}} | ||
| } | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
26-char prefix differs from other limits – unify constant
[:26] conflicts with 25 (frontend) and 30 (elsewhere). Use a single MAX_SERVER_NAME_PREFIX constant shared with the frontend to avoid mismatches.
🤖 Prompt for AI Agents
In src/backend/base/langflow/api/v1/mcp_projects.py around lines 392 to 396, the
code uses a hardcoded 26-character limit for the server name prefix, which
conflicts with other limits like 25 in the frontend and 30 elsewhere. Define a
shared constant MAX_SERVER_NAME_PREFIX and replace the hardcoded 26 with this
constant to unify the limit across the codebase and avoid mismatches.
There was a problem hiding this comment.
MAX_SERVER_NAME_PREFIX @lucaseduoli This is a Good review can you add it?
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
edwinjosechittilappilly
left a comment
There was a problem hiding this comment.
use MAX_SERVER_NAME_PREFIX It seems to make the backend config consistent.
…ation`) Here is an optimized version of your function. - **Optimize membership test by converting `existing_names` to a `set` (if not already) for `O(1)` lookup.** - **Avoid repeated string slicing and concatenation by precomputing values where possible.** - **Minimize the number of function calls in the loop.** **Key changes:** - Ensure `existing_names` is a set for much faster lookup. - Avoid redundant `len(base_name)` and `len(suffix)` calculation. - Minimize slice operations by reusing precomputed string parts. **All function signatures and return values are preserved.**
| name = base_name[:max_length] | ||
| if name not in existing_names: | ||
| return name | ||
| i = 1 | ||
| while True: | ||
| suffix = f"_{i}" | ||
| truncated_base = base_name[: max_length - len(suffix)] | ||
| candidate = f"{truncated_base}{suffix}" |
There was a problem hiding this comment.
⚡️Codeflash found 94% (0.94x) speedup for get_unique_name in src/backend/base/langflow/base/mcp/util.py
⏱️ Runtime : 2.63 milliseconds → 1.35 milliseconds (best of 136 runs)
📝 Explanation and details
Here is an optimized version of your function.- Optimize membership test by converting
existing_namesto aset(if not already) forO(1)lookup. - Avoid repeated string slicing and concatenation by precomputing values where possible.
- Minimize the number of function calls in the loop.
Key changes:
- Ensure
existing_namesis a set for much faster lookup. - Avoid redundant
len(base_name)andlen(suffix)calculation. - Minimize slice operations by reusing precomputed string parts.
All function signatures and return values are preserved.
✅ Correctness verification report:
| Test | Status |
|---|---|
| ⚙️ Existing Unit Tests | 🔘 None Found |
| 🌀 Generated Regression Tests | ✅ 95 Passed |
| ⏪ Replay Tests | 🔘 None Found |
| 🔎 Concolic Coverage Tests | 🔘 None Found |
| 📊 Tests Coverage | 100.0% |
🌀 Generated Regression Tests Details
import pytest # used for our unit tests
from langflow.base.mcp.util import get_unique_name
# unit tests
# ------------------------
# Basic Test Cases
# ------------------------
def test_basic_unique_name_available():
# Name is not in existing_names, and fits within max_length
codeflash_output = get_unique_name("foo", 10, set())
codeflash_output = get_unique_name("bar", 3, set())
codeflash_output = get_unique_name("baz", 4, {"qux"})
def test_basic_name_truncation():
# base_name longer than max_length, not in existing_names
codeflash_output = get_unique_name("longname", 4, set())
codeflash_output = get_unique_name("abcdef", 3, set())
# base_name exactly max_length
codeflash_output = get_unique_name("hello", 5, set())
def test_basic_suffix_generation():
# base_name in existing_names, so suffix needed
codeflash_output = get_unique_name("foo", 10, {"foo"})
codeflash_output = get_unique_name("foo", 10, {"foo", "foo_1"})
# base_name longer than max_length, suffix needed
codeflash_output = get_unique_name("longname", 6, {"longna"})
# base_name exactly max_length, suffix needed
codeflash_output = get_unique_name("hello", 5, {"hello"})
def test_basic_multiple_existing_names():
# Multiple conflicting names, should pick next available suffix
existing = {"foo", "foo_1", "foo_2"}
codeflash_output = get_unique_name("foo", 10, existing)
existing = {"bar", "bar_1", "bar_2", "bar_3"}
codeflash_output = get_unique_name("bar", 6, existing)
# ------------------------
# Edge Test Cases
# ------------------------
def test_edge_empty_base_name():
# Empty base_name
codeflash_output = get_unique_name("", 5, set())
# Empty base_name, but "" is taken
codeflash_output = get_unique_name("", 5, {""})
# Empty base_name, "" and "_1" taken
codeflash_output = get_unique_name("", 5, {"", "_1"})
def test_edge_zero_max_length():
# max_length = 0, only possible name is ""
codeflash_output = get_unique_name("abc", 0, set())
# "" is taken, so next is "_1", but max_length=0, so truncated base is ""
codeflash_output = get_unique_name("abc", 0, {""})
codeflash_output = get_unique_name("abc", 0, {"", "_1"})
def test_edge_max_length_smaller_than_suffix():
# max_length is less than length needed for suffix, so base truncates to ""
# "_1" is 2 chars, max_length=1, so base is "", candidate is "_1"
codeflash_output = get_unique_name("foo", 1, set())
codeflash_output = get_unique_name("foo", 1, {"f"})
codeflash_output = get_unique_name("foo", 1, {"f", "_1"})
# max_length=2, "_1" is 2 chars, so base is "", candidate is "_1"
codeflash_output = get_unique_name("foo", 2, {"fo"})
def test_edge_suffix_collision_with_truncated_names():
# base_name and base_name_1 both in existing_names, should skip to _2
existing = {"foo", "foo_1"}
codeflash_output = get_unique_name("foo", 6, existing)
# base_name truncates, and truncated+suffix collides
existing = {"longn", "longn_1"}
codeflash_output = get_unique_name("longname", 6, existing)
def test_edge_suffix_wraps_base_name_to_empty():
# base_name is shorter than suffix, so candidate is just the suffix
codeflash_output = get_unique_name("a", 2, {"a"})
codeflash_output = get_unique_name("a", 2, {"a", "_1"})
def test_edge_existing_names_with_similar_prefixes():
# Existing names are similar but not identical
existing = {"foo", "foo_1", "foo_10", "foo_2"}
codeflash_output = get_unique_name("foo", 10, existing)
# Suffixes with gaps
existing = {"foo", "foo_1", "foo_3"}
codeflash_output = get_unique_name("foo", 10, existing)
def test_edge_non_string_existing_names():
# existing_names contains non-string elements (should not crash, but we expect only string comparison)
existing = {"foo", 123, None}
codeflash_output = get_unique_name("foo", 10, existing)
# If base_name is not in existing_names as string, should still return base_name
existing = {123, None}
codeflash_output = get_unique_name("foo", 10, existing)
def test_edge_suffix_number_grows():
# Suffixes with double digits
existing = {"foo"} | {f"foo_{i}" for i in range(1, 12)}
codeflash_output = get_unique_name("foo", 10, existing)
def test_edge_max_length_exactly_suffix_length():
# max_length matches the length of the suffix
# "_1" is 2 chars, so max_length=2, base is truncated to "", candidate is "_1"
codeflash_output = get_unique_name("foo", 2, {"fo"})
# If "_1" is taken, next is "_2"
codeflash_output = get_unique_name("foo", 2, {"fo", "_1"})
def test_edge_base_name_with_underscores():
# base_name already ends with an underscore, suffix should still be appended
existing = {"foo_"}
codeflash_output = get_unique_name("foo_", 5, existing)
# base_name with multiple underscores
existing = {"foo__"}
codeflash_output = get_unique_name("foo__", 6, existing)
def test_edge_existing_names_with_similar_suffixes():
# existing_names has similar but not exact suffixes
existing = {"foo_10", "foo_11"}
codeflash_output = get_unique_name("foo", 10, existing)
# base_name taken, but only high-numbered suffixes
existing = {"foo", "foo_10", "foo_11"}
codeflash_output = get_unique_name("foo", 10, existing)
# ------------------------
# Large Scale Test Cases
# ------------------------
def test_large_many_existing_names():
# 1000 existing names, should pick next available
existing = {f"name_{i}" for i in range(1000)}
codeflash_output = get_unique_name("name", 10, existing)
# All possible "name" and "name_1" to "name_999" taken, should return "name_1000"
existing = {"name"} | {f"name_{i}" for i in range(1, 1000)}
codeflash_output = get_unique_name("name", 10, existing)
def test_large_long_base_name_and_max_length():
# base_name is very long, max_length is large, no existing names
long_name = "a" * 1000
codeflash_output = get_unique_name(long_name, 999, set())
# base_name is very long, but max_length is small
codeflash_output = get_unique_name(long_name, 5, set())
def test_large_suffix_generation_with_truncation():
# base_name is long, max_length is small, and many suffixes are taken
base_name = "abcdefghij"
max_length = 5
# Take "abcde", "abcd_1", ..., "abcd_9"
existing = {base_name[:max_length]} | {f"{base_name[:max_length-2]}_{i}" for i in range(1, 10)}
codeflash_output = get_unique_name(base_name, max_length, existing)
def test_large_performance_many_collisions():
# Simulate many collisions to test performance
base_name = "foo"
max_length = 7
# Take "foo", "foo_1", ..., "foo_999"
existing = {"foo"} | {f"foo_{i}" for i in range(1, 1000)}
codeflash_output = get_unique_name(base_name, max_length, existing)
def test_large_existing_names_with_varied_suffixes():
# existing_names has a mix of numbers and similar names
base_name = "item"
max_length = 8
existing = {f"item_{i}" for i in range(1, 500)} | {"item", "item_500", "item_999"}
codeflash_output = get_unique_name(base_name, max_length, existing)
def test_large_existing_names_with_truncation_and_suffix():
# base_name is long, max_length is small, and all possible truncated+suffix names are taken up to a point
base_name = "abcdefghijk"
max_length = 6
# "abcdef", "abcde_1" to "abcde_99" taken
existing = {base_name[:max_length]} | {f"{base_name[:max_length-2]}_{i}" for i in range(1, 100)}
codeflash_output = get_unique_name(base_name, max_length, existing)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import pytest # used for our unit tests
from langflow.base.mcp.util import get_unique_name
# unit tests
# -------------------- BASIC TEST CASES --------------------
def test_basic_unique_name_not_in_existing():
# Simple case: base_name fits, not in existing_names
codeflash_output = get_unique_name("foo", 10, set())
codeflash_output = get_unique_name("bar", 10, {"baz", "qux"})
def test_basic_unique_name_with_truncation():
# base_name longer than max_length, should be truncated
codeflash_output = get_unique_name("longname", 4, set())
codeflash_output = get_unique_name("abcdefgh", 5, {"a", "ab"})
def test_basic_unique_name_with_existing():
# base_name is present in existing_names, should add suffix
codeflash_output = get_unique_name("foo", 10, {"foo"})
codeflash_output = get_unique_name("foo", 10, {"foo", "foo_1"})
def test_basic_suffix_truncation():
# Suffix causes truncation of base_name
codeflash_output = get_unique_name("foobar", 6, {"foobar"})
codeflash_output = get_unique_name("foobar", 6, {"foobar", "foob_1"})
def test_basic_suffix_multiple_digits():
# Suffix with multiple digits, ensure correct truncation
existing = {"foo", "fo_1", "fo_2", "fo_3", "fo_4", "fo_5", "fo_6", "fo_7", "fo_8", "fo_9", "fo_10"}
codeflash_output = get_unique_name("foo", 4, existing)
# -------------------- EDGE TEST CASES --------------------
def test_edge_base_name_exact_max_length():
# base_name exactly max_length, not in existing_names
codeflash_output = get_unique_name("abcde", 5, set())
# base_name exactly max_length, but in existing_names
codeflash_output = get_unique_name("abcde", 5, {"abcde"})
def test_edge_base_name_shorter_than_max_length():
# base_name shorter than max_length
codeflash_output = get_unique_name("a", 10, set())
codeflash_output = get_unique_name("a", 10, {"a"})
def test_edge_base_name_empty():
# base_name is empty
codeflash_output = get_unique_name("", 5, set())
codeflash_output = get_unique_name("", 5, {""})
# If max_length is 0, only possible name is ""
codeflash_output = get_unique_name("foo", 0, set())
codeflash_output = get_unique_name("foo", 0, {""})
def test_edge_max_length_smaller_than_suffix():
# max_length smaller than base_name + suffix, must truncate base_name
codeflash_output = get_unique_name("abcdef", 4, {"abcd"})
# Suffix longer than max_length: edge case, should handle gracefully
# For max_length=2, suffix is "_1" (2 chars), so base_name is truncated to 0
codeflash_output = get_unique_name("foo", 2, {"fo"})
# If "_1" is also taken, next is "_2"
codeflash_output = get_unique_name("foo", 2, {"fo", "_1"})
def test_edge_suffix_causes_empty_base():
# max_length == len(suffix), so base_name is empty
codeflash_output = get_unique_name("foo", 2, set())
codeflash_output = get_unique_name("foo", 2, {"fo"})
# If "_1" is taken
codeflash_output = get_unique_name("foo", 2, {"fo", "_1"})
def test_edge_non_ascii_names():
# Non-ASCII base_name
codeflash_output = get_unique_name("测试", 5, set())
codeflash_output = get_unique_name("测试", 2, {"测试"})
# Emoji
codeflash_output = get_unique_name("😀😃😄", 4, set())
codeflash_output = get_unique_name("😀😃😄", 2, {"😀😃"})
def test_edge_existing_names_with_similar_suffixes():
# Existing names with similar suffixes but not matching the pattern
existing = {"foo", "foo1", "foo_1", "foo_2"}
codeflash_output = get_unique_name("foo", 10, existing)
# Existing names with gaps in the suffix numbering
existing = {"foo", "foo_1", "foo_3"}
codeflash_output = get_unique_name("foo", 10, existing)
def test_edge_existing_names_as_list():
# existing_names as a list instead of set
codeflash_output = get_unique_name("foo", 10, ["foo", "foo_1"])
def test_edge_suffix_collision_with_base_name():
# base_name that already ends with _1, _2, etc.
existing = {"foo_1"}
codeflash_output = get_unique_name("foo_1", 10, existing)
existing = {"foo_1", "foo_1_1"}
codeflash_output = get_unique_name("foo_1", 10, existing)
def test_edge_max_length_zero():
# max_length is zero, only possible name is ""
codeflash_output = get_unique_name("foo", 0, set())
codeflash_output = get_unique_name("foo", 0, {""})
codeflash_output = get_unique_name("foo", 0, {"", "_1"})
def test_edge_suffix_exceeds_max_length():
# Suffix is longer than max_length, should still return a name
codeflash_output = get_unique_name("foo", 2, {"fo", "_1", "_2", "_3"})
# -------------------- LARGE SCALE TEST CASES --------------------
def test_large_many_existing_names():
# 1000 existing names, all possible foo, foo_1, ..., foo_999
existing = {"foo"} | {f"foo_{i}" for i in range(1, 1000)}
# Next unique should be foo_1000
codeflash_output = get_unique_name("foo", 10, existing)
def test_large_many_collisions_with_truncation():
# base_name="abcdefghij", max_length=8, existing names: abcdefgh, abcdef_1, ..., abcdef_99
existing = {"abcdefgh"} | {f"abcdef_{i}" for i in range(1, 100)}
# Next should be abcdef_100
codeflash_output = get_unique_name("abcdefghij", 8, existing)
def test_large_existing_names_with_gaps():
# Large set with gaps in suffixes
existing = {"foo"} | {f"foo_{i}" for i in range(1, 1000) if i != 500}
# Should fill the gap
codeflash_output = get_unique_name("foo", 10, existing)
def test_large_performance_many_names():
# Stress test: 999 names taken, base_name="bar", max_length=5
existing = {"bar"} | {f"ba_{i}" for i in range(1, 1000)}
# Next should be ba_1000
codeflash_output = get_unique_name("bar", 5, existing)
def test_large_performance_suffix_length_growth():
# Suffix length increases, causing more truncation
existing = {"a"} | {f"_{i}" for i in range(1, 1000)}
# For base_name="a", max_length=2, all "_1"..."_999" taken
codeflash_output = get_unique_name("a", 2, existing)
def test_large_existing_names_as_list():
# existing_names as a large list
existing = ["foo"] + [f"foo_{i}" for i in range(1, 500)]
codeflash_output = get_unique_name("foo", 10, existing)
# -------------------- DETERMINISM TEST --------------------
def test_determinism_repeated_calls():
# Multiple calls with same input should yield same output
existing = {"foo", "foo_1", "foo_2"}
codeflash_output = get_unique_name("foo", 10, existing); result1 = codeflash_output
codeflash_output = get_unique_name("foo", 10, existing); result2 = codeflash_output
# -------------------- TYPE AND ERROR HANDLING --------------------
def test_type_error_on_bad_existing_names():
# existing_names must be iterable (set/list/tuple)
with pytest.raises(TypeError):
get_unique_name("foo", 5, None)
with pytest.raises(TypeError):
get_unique_name("foo", 5, 123)
def test_type_error_on_bad_max_length():
# max_length must be int >= 0
with pytest.raises(TypeError):
get_unique_name("foo", "5", set())
with pytest.raises(ValueError):
get_unique_name("foo", -1, set())
def test_type_error_on_bad_base_name():
# base_name must be str
with pytest.raises(TypeError):
get_unique_name(123, 5, set())
with pytest.raises(TypeError):
get_unique_name(None, 5, set())
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.To test or edit this optimization locally git merge codeflash/optimize-pr8494-2025-06-12T19.01.15
Click to see suggested changes
| name = base_name[:max_length] | |
| if name not in existing_names: | |
| return name | |
| i = 1 | |
| while True: | |
| suffix = f"_{i}" | |
| truncated_base = base_name[: max_length - len(suffix)] | |
| candidate = f"{truncated_base}{suffix}" | |
| # Convert existing_names to set for faster lookup if it's not already a set | |
| if not isinstance(existing_names, set): | |
| existing_names = set(existing_names) | |
| name = base_name[:max_length] | |
| if name not in existing_names: | |
| return name | |
| # Precompute the part of base_name that can be re-used | |
| base_name_len = len(base_name) | |
| i = 1 | |
| while True: | |
| suffix = f"_{i}" | |
| allowed_base_len = max_length - len(suffix) | |
| # Avoid extra slicing if allowed_base_len == base_name_len | |
| if allowed_base_len >= base_name_len: | |
| candidate = base_name + suffix | |
| else: | |
| candidate = base_name[:allowed_base_len] + suffix |
…i#8494) * updated mcp backend to truncate tools name to 30 chars * updated frontend to truncate tools with 30 chars and truncate project name with 26 chars * changed it to not exceed 25 * updated one click install to truncate at 26 * updated name * used constants and helper functions to refactor code * updated constants --------- Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This pull request focuses on improving the handling of name truncation and uniqueness for various entities across the backend and frontend. Key changes include increasing the maximum allowed length for names, ensuring unique names by appending numeric suffixes when necessary, and updating related logic in both backend and frontend components.
Backend Changes
Name Truncation and Uniqueness:
async def handle_list_tools()insrc/backend/base/langflow/api/v1/mcp.pyto truncate names to a maximum of 30 characters and ensure uniqueness by appending numeric suffixes when duplicates are detected.async def handle_list_project_tools()insrc/backend/base/langflow/api/v1/mcp_projects.pyto apply similar truncation and uniqueness logic for project tool names. [1] [2]MCP Server Name Length:
async def install_mcp_config()andasync def check_installed_mcp_servers()insrc/backend/base/langflow/api/v1/mcp_projects.py. [1] [2]Frontend Changes
Name Length Adjustments:
AddMcpServerModal(src/frontend/src/modals/addMcpServerModal/index.tsx). [1] [2] [3]McpServerTab(src/frontend/src/pages/MainPage/pages/homePage/components/McpServerTab.tsx) to allow up to 25 characters.extractMcpServersFromJsoninsrc/frontend/src/utils/mcpUtils.tsto reflect the increased name length limit of 30 characters.Summary by CodeRabbit