Skip to main content
Glama

rename_session

Change session titles by adding descriptive prefixes to organize Claude conversations within project folders.

Instructions

Rename a session by adding a title prefix to the first message

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_nameYesProject folder name
session_idYesSession ID (filename without .jsonl)
new_titleYesNew title to add as prefix

Implementation Reference

  • Core handler function that modifies the session's JSONL file by prefixing the new title to the first user message's text content, handling queue-operations and IDE tags appropriately.
    def rename_session(project_name: str, session_id: str, new_title: str) -> bool: """Rename a session by adding title prefix to first message.""" base_path = get_base_path() project_path = base_path / project_name jsonl_file = project_path / f"{session_id}.jsonl" if not jsonl_file.exists(): return False lines = [] first_user_idx = -1 original_message = None try: with open(jsonl_file, 'r', encoding='utf-8') as f: for i, line in enumerate(f): lines.append(line) line_stripped = line.strip() if line_stripped: try: entry = json.loads(line_stripped) entry_type = entry.get('type') if entry_type == 'queue-operation' and original_message is None: if entry.get('operation') == 'enqueue': content_arr = entry.get('content', []) for item in content_arr: if isinstance(item, dict) and item.get('type') == 'text': txt = item.get('text', '') if txt and not txt.strip().startswith('<ide_'): original_message = txt break if entry_type == 'user' and first_user_idx == -1: first_user_idx = i except json.JSONDecodeError: pass if first_user_idx == -1: return False entry = json.loads(lines[first_user_idx].strip()) message = entry.get('message', {}) content_list = message.get('content', []) if original_message is not None: text_idx = -1 for idx, item in enumerate(content_list): if isinstance(item, dict) and item.get('type') == 'text': text_content = item.get('text', '') if text_content.strip().startswith('<ide_'): continue text_idx = idx break if text_idx >= 0: content_list[text_idx]['text'] = f"{new_title}\n\n{original_message}" else: insert_pos = 0 for idx, item in enumerate(content_list): if isinstance(item, dict) and item.get('type') == 'text': text_content = item.get('text', '') if text_content.strip().startswith('<ide_'): insert_pos = idx + 1 content_list.insert(insert_pos, {'type': 'text', 'text': f"{new_title}\n\n{original_message}"}) else: for item in content_list: if isinstance(item, dict) and item.get('type') == 'text': old_text = item.get('text', '') old_text = re.sub(r'^[^\n]+\n\n', '', old_text) item['text'] = f"{new_title}\n\n{old_text}" break entry['message']['content'] = content_list lines[first_user_idx] = json.dumps(entry, ensure_ascii=False) + '\n' with open(jsonl_file, 'w', encoding='utf-8') as f: f.writelines(lines) return True except Exception: return False
  • Registers the 'rename_session' tool with the MCP server, defining its name, description, and input schema.
    Tool( name="rename_session", description="Rename a session by adding a title prefix to the first message", inputSchema={ "type": "object", "properties": { "project_name": { "type": "string", "description": "Project folder name" }, "session_id": { "type": "string", "description": "Session ID (filename without .jsonl)" }, "new_title": { "type": "string", "description": "New title to add as prefix" } }, "required": ["project_name", "session_id", "new_title"] } ),
  • MCP tool dispatcher branch that extracts arguments and calls the rename_session handler function.
    elif name == "rename_session": project_name = arguments.get("project_name", "") session_id = arguments.get("session_id", "") new_title = arguments.get("new_title", "") success = rename_session(project_name, session_id, new_title) result = {"success": success, "message": "Session renamed" if success else "Failed to rename session"}
  • Helper function used in listing sessions to parse titles from session files, related to how titles are handled.
    def parse_session_summary(file_path: Path) -> dict | None: """Parse session file for summary info.""" session_id = file_path.stem info = { "session_id": session_id, "title": f"Session {session_id[:8]}", "message_count": 0, "created_at": None, "updated_at": None, } try: with open(file_path, 'r', encoding='utf-8') as f: first_user_content = None for line in f: line = line.strip() if not line: continue try: entry = json.loads(line) entry_type = entry.get('type') if entry_type in ('user', 'assistant'): info["message_count"] += 1 timestamp = entry.get('timestamp', '') if timestamp: if not info["created_at"] or timestamp < info["created_at"]: info["created_at"] = timestamp if not info["updated_at"] or timestamp > info["updated_at"]: info["updated_at"] = timestamp if entry_type == 'user' and first_user_content is None: message = entry.get('message', {}) content_list = message.get('content', []) for item in content_list: if isinstance(item, dict) and item.get('type') == 'text': text = item.get('text', '').strip() text = re.sub(r'<ide_[^>]*>.*?</ide_[^>]*>', '', text, flags=re.DOTALL).strip() if text: first_user_content = text break except json.JSONDecodeError: continue if first_user_content: if '\n\n' in first_user_content: info["title"] = first_user_content.split('\n\n')[0][:100] elif '\n' in first_user_content: info["title"] = first_user_content.split('\n')[0][:100] else: info["title"] = first_user_content[:100] except Exception: return None return info if info["message_count"] > 0 else None def delete_session(project_name: str, session_id: str) -> bool: """Delete a session (move to .bak folder, or delete if empty).""" base_path = get_base_path() project_path = base_path / project_name jsonl_file = project_path / f"{session_id}.jsonl" if not jsonl_file.exists(): return False # If file is empty (0 bytes), just delete it without backing up if jsonl_file.stat().st_size == 0: jsonl_file.unlink() return True backup_dir = base_path / ".bak" backup_dir.mkdir(exist_ok=True) backup_file = backup_dir / f"{project_name}_{session_id}.jsonl" jsonl_file.rename(backup_file) return True def rename_session(project_name: str, session_id: str, new_title: str) -> bool: """Rename a session by adding title prefix to first message.""" base_path = get_base_path() project_path = base_path / project_name jsonl_file = project_path / f"{session_id}.jsonl" if not jsonl_file.exists(): return False lines = [] first_user_idx = -1 original_message = None try: with open(jsonl_file, 'r', encoding='utf-8') as f: for i, line in enumerate(f): lines.append(line) line_stripped = line.strip() if line_stripped: try: entry = json.loads(line_stripped) entry_type = entry.get('type') if entry_type == 'queue-operation' and original_message is None: if entry.get('operation') == 'enqueue': content_arr = entry.get('content', []) for item in content_arr: if isinstance(item, dict) and item.get('type') == 'text': txt = item.get('text', '') if txt and not txt.strip().startswith('<ide_'): original_message = txt break if entry_type == 'user' and first_user_idx == -1: first_user_idx = i except json.JSONDecodeError: pass if first_user_idx == -1: return False entry = json.loads(lines[first_user_idx].strip()) message = entry.get('message', {}) content_list = message.get('content', []) if original_message is not None: text_idx = -1 for idx, item in enumerate(content_list): if isinstance(item, dict) and item.get('type') == 'text': text_content = item.get('text', '') if text_content.strip().startswith('<ide_'): continue text_idx = idx break if text_idx >= 0: content_list[text_idx]['text'] = f"{new_title}\n\n{original_message}" else: insert_pos = 0 for idx, item in enumerate(content_list): if isinstance(item, dict) and item.get('type') == 'text': text_content = item.get('text', '') if text_content.strip().startswith('<ide_'): insert_pos = idx + 1 content_list.insert(insert_pos, {'type': 'text', 'text': f"{new_title}\n\n{original_message}"}) else: for item in content_list: if isinstance(item, dict) and item.get('type') == 'text': old_text = item.get('text', '') old_text = re.sub(r'^[^\n]+\n\n', '', old_text) item['text'] = f"{new_title}\n\n{old_text}" break entry['message']['content'] = content_list lines[first_user_idx] = json.dumps(entry, ensure_ascii=False) + '\n' with open(jsonl_file, 'w', encoding='utf-8') as f: f.writelines(lines) return True except Exception: return False

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DrumRobot/claude-session-manager'

If you have feedback or need assistance with the MCP directory API, please join our Discord server