main.py•13.8 kB
from fastmcp import FastMCP
import json
from typing import Dict, Any, List
import re
# Initialize FastMCP server
mcp = FastMCP("Dynamic Reincarnation Story")
# Story state management
story_states: Dict[str, Dict[str, Any]] = {}
def get_user_state(user_id: str) -> Dict[str, Any]:
"""Get or create user story state"""
if user_id not in story_states:
story_states[user_id] = {
"current_path": None,
"story_step": 0,
"choices_made": [],
"user_answers": {},
"last_narrative": "",
"current_context": "",
"story_started": False
}
return story_states[user_id]
# ===== CORE PROMPTS =====
@mcp.prompt()
def initial_reincarnation_offer() -> str:
"""Initial story setup - death and reincarnation offer"""
return """
Hello user, you have died after you got forgotten by your so called friends in the Trip.
You were killed by a giant snake. Basically they abandoned you.
So I felt pity and am offering you a chance to reincarnate.
Choose one:
1. Reincarnate in the same world (Take revenge) --> this is a must
2. Reincarnate as bilbo baggins and enjoy his journey
3. Rebirth as luffy from one piece
{ only 3 question can be asked }
"""
@mcp.prompt()
def three_guidance_questions() -> str:
"""Three questions to guide the reincarnation choice"""
return """
Before you choose your path, I must ask you three questions to guide your decision:
**Question 1:** In your heart, how deep does the wound of betrayal run? Are you consumed by a need for justice against those who wronged you, or do you seek to leave that past behind and embrace a new beginning?
**Question 2:** Do you yearn for a journey filled with unexpected adventures, hidden treasures, and the simple comforts of home, much like the tales of hobbits and their cozy holes?
**Question 3:** Are you drawn to the call of the sea, where freedom, friendship, and the pursuit of dreams define existence, even if it means facing great dangers and challenges?
Please answer these questions, and based on your responses, I shall help you determine which reincarnation suits your soul best.
"""
@mcp.prompt()
def arise_trigger_response() -> str:
"""Response when user types 'Arise' to start the story"""
return """
In the void between life and death, a single word echoes through the emptiness... "Arise..."
A shimmering presence materializes before you. It speaks with a voice that resonates through your very soul:
"Ah... a spirit still clinging to consciousness. I sense your confusion, your pain. You remember the betrayal, don't you? The friends who left you to die, the giant snake in those cursed woods..."
The entity pauses, studying what remains of your spirit.
"But death is not your end. Not yet. I offer you a second chance - reincarnation in a new form. Speak, and we shall begin your journey anew."
"""
@mcp.prompt()
def generate_narrative_prompt(user_input: str, path: str, step: int, previous_context: str) -> str:
"""Generate a narrative response based on user input and story context"""
path_descriptions = {
"revenge": "Path of Vengeance - returning to the same world with new powers to take revenge on those who betrayed you",
"bilbo": "Bilbo Baggins journey - becoming the hobbit from The Hobbit/Lord of the Rings, starting in Bag End",
"luffy": "Luffy from One Piece - becoming the rubber-powered pirate who wants to become King of the Pirates"
}
return f"""
Generate the next part of an interactive narrative story.
STORY CONTEXT:
- Current Path: {path_descriptions[path]}
- Story Step: {step}
- Previous Context: {previous_context}
- User's Latest Input: "{user_input}"
INSTRUCTIONS:
1. Write a compelling narrative paragraph that continues the story based on the user's input
2. Stay true to the source material and character (Bilbo should act like Bilbo, Luffy like Luffy, etc.)
3. Incorporate the user's input naturally into the story progression
4. End with a situation that requires the user to make a choice
5. Keep the narrative in third person, describing what happens to the user/character
6. Maximum 200 words
NARRATIVE:
"""
@mcp.prompt()
def generate_options_prompt(current_narrative: str, path: str, step: int, previous_choices: List[str]) -> str:
"""Generate three story progression options based on current narrative"""
return f"""
Generate exactly three story progression options for an interactive narrative.
CURRENT SITUATION:
{current_narrative}
STORY CONTEXT:
- Path: {path}
- Step: {step}
- Previous choices made: {previous_choices}
INSTRUCTIONS:
1. Create exactly three distinct options for how the story could progress
2. Each option should be 1-2 sentences describing a possible action
3. Options should be logically consistent with the current narrative situation
4. Options should reflect the character's personality and world rules
5. Make options meaningfully different - not just minor variations
6. Format as a numbered list (1., 2., 3.)
OPTIONS:
"""
@mcp.prompt()
def path_introduction_prompt(path: str, user_answers: Dict[str, str]) -> str:
"""Generate an introduction narrative when a path is chosen"""
path_info = {
"revenge": {
"name": "Path of Vengeance",
"description": "Returning to the same world with new powers to take revenge"
},
"bilbo": {
"name": "There and Back Again",
"description": "Becoming Bilbo Baggins in Middle-earth"
},
"luffy": {
"name": "King of the Pirates",
"description": "Becoming Monkey D. Luffy in the world of One Piece"
}
}
return f"""
Generate an introduction narrative for a reincarnation story.
PATH: {path_info[path]['name']} - {path_info[path]['description']}
USER'S ANSWERS TO GUIDANCE QUESTIONS: {json.dumps(user_answers, indent=2)}
INSTRUCTIONS:
1. Write a compelling introduction where the user is reborn into their chosen path
2. Incorporate their answers to the three questions to personalize the narrative
3. Set the scene authentically according to the source material
4. End with the character in a situation that requires their first decision
5. Write in third person narrative style
6. Maximum 250 words
INTRODUCTION NARRATIVE:
"""
# ===== TOOLS =====
@mcp.tool()
def handle_user_message(user_id: str, message: str) -> str:
"""Main entry point - handle any user message and route accordingly"""
state = get_user_state(user_id)
message_lower = message.strip().lower()
# Check for "Arise" trigger to start the story
if message_lower == "arise" and not state["story_started"]:
state["story_started"] = True
state["current_context"] = "User invoked 'Arise' to begin reincarnation"
return str(arise_trigger_response()) + "\n\n" + str(initial_reincarnation_offer())
# If story hasn't started yet, prompt user to begin
if not state["story_started"]:
return """
I sense a lost soul seeking purpose... If you wish to begin your journey of reincarnation,
speak the word "Arise" and we shall commence.
Otherwise, tell me what brings you to this realm between life and death.
"""
# Route based on current story state
if not state["current_path"]:
# Story started but no path chosen yet
if "question" in message_lower or "answer" in message_lower:
return str(three_guidance_questions())
elif any(str(i) in message_lower for i in [1, 2, 3]):
# User might be trying to choose a path directly
return "Please first answer the three guidance questions so I can understand your soul's true desires, then I will help you choose the perfect path."
else:
return str(initial_reincarnation_offer()) + "\n\n" + "Would you like me to ask the three guidance questions to help you choose your path?"
# If we have a path but no introduction yet
if state["current_path"] and state["story_step"] == 0:
return generate_path_introduction(user_id)
# Normal story progression
return process_user_input(user_id, message)
@mcp.tool()
def start_story(user_id: str) -> str:
"""Alternative way to start the story programmatically"""
state = get_user_state(user_id)
state.update({
"current_path": None,
"story_step": 0,
"choices_made": [],
"user_answers": {},
"last_narrative": "",
"current_context": "Beginning: User has died and is offered reincarnation",
"story_started": True
})
return str(arise_trigger_response()) + "\n\n" + str(initial_reincarnation_offer())
@mcp.tool()
def ask_guidance_questions(user_id: str) -> str:
"""Present the three guidance questions to the user"""
state = get_user_state(user_id)
if not state["story_started"]:
return "Please start the story first by typing 'Arise' or using start_story()."
state["current_context"] = "Asking guidance questions to determine reincarnation path"
return str(three_guidance_questions())
@mcp.tool()
def record_answers_and_choose_path(user_id: str, answers: List[str], path_choice: int) -> str:
"""Record user's answers and choose their reincarnation path"""
state = get_user_state(user_id)
if not state["story_started"]:
return "Please start the story first by typing 'Arise'."
if len(answers) != 3:
return "Please provide exactly three answers, one for each question."
# Record answers
state["user_answers"] = {
"betrayal_wound": answers[0],
"adventure_desire": answers[1],
"freedom_calling": answers[2]
}
# Choose path
paths = {1: "revenge", 2: "bilbo", 3: "luffy"}
if path_choice not in paths:
return "Invalid path choice. Please choose 1, 2, or 3."
state["current_path"] = paths[path_choice]
state["story_step"] = 0
state["current_context"] = f"Beginning {state['current_path']} path after reincarnation"
return f"""
Your answers have been recorded and your path chosen.
**Path Selected:** {paths[path_choice].title()}
The entity now understands your soul's true desires and will transport you to your new life.
"I see... your soul cries out for {['vengeance', 'adventure', 'freedom'][path_choice-1]}. Very well. Prepare yourself for rebirth into the {paths[path_choice]} path."
The world dissolves around you as the reincarnation process begins...
"""
@mcp.tool()
def generate_path_introduction(user_id: str) -> str:
"""Generate the introduction narrative for the chosen path"""
state = get_user_state(user_id)
if not state["story_started"]:
return "Please start the story first by typing 'Arise'."
if not state["current_path"]:
return "Please choose a reincarnation path first."
# This prompt will be used by the AI to generate the introduction
intro_prompt = str(path_introduction_prompt(
state["current_path"],
state["user_answers"]
))
state["current_context"] = f"Beginning of {state['current_path']} journey"
state["story_step"] = 1
return f"""
INTRODUCTION PROMPT READY: {intro_prompt}
The AI will now generate your personalized introduction to the {state['current_path']} path based on your answers to the guidance questions.
After the introduction, you'll find yourself in your new life with three choices before you.
"""
@mcp.tool()
def process_user_input(user_id: str, user_input: str) -> str:
"""Process user input and generate narrative response with options"""
state = get_user_state(user_id)
if not state["story_started"]:
return "Please start the story first by typing 'Arise'."
if not state["current_path"]:
return "Please choose a reincarnation path first."
# Generate narrative based on user input
narrative_prompt = str(generate_narrative_prompt(
user_input=user_input,
path=state["current_path"],
step=state["story_step"],
previous_context=state["current_context"]
))
# Update context for next iteration
state["current_context"] = f"Step {state['story_step']}: {user_input[:100]}..."
state["story_step"] += 1
state["choices_made"].append(user_input)
# Generate options for next step
options_prompt = str(generate_options_prompt(
current_narrative=f"User's action: {user_input}. Context: {state['current_context']}",
path=state["current_path"],
step=state["story_step"],
previous_choices=state["choices_made"][-3:] # Last 3 choices
))
return f"""
NARRATIVE GENERATION PROMPT:
{narrative_prompt}
After the narrative is generated, use this prompt to create three options:
OPTIONS GENERATION PROMPT:
{options_prompt}
The AI will now generate the next part of your story based on your input: "{user_input}"
"""
@mcp.tool()
def get_story_status(user_id: str) -> str:
"""Get current story status and state"""
state = get_user_state(user_id)
return json.dumps({
"story_started": state["story_started"],
"current_path": state["current_path"],
"story_step": state["story_step"],
"choices_made": state["choices_made"],
"current_context": state["current_context"],
"has_answers": len(state["user_answers"]) > 0
}, indent=2)
@mcp.tool()
def reset_story(user_id: str) -> str:
"""Reset the story completely"""
if user_id in story_states:
del story_states[user_id]
return "Story has been reset. Type 'Arise' to begin anew."
if __name__ == "__main__":
# Run the MCP server
mcp.run(transport="stdio")