This commit is contained in:
And-Lyd 2026-08-04 22:43:08 +08:00 committed by GitHub
commit 665271419e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 1117 additions and 0 deletions

View File

@ -0,0 +1,117 @@
# Codex and Claude MCP Setup
## Goal
Use MiroFish as a shared prediction engine through one MCP server so:
- Codex can build and operate simulation flows
- Claude can reason over the same simulation and report state
- both tools stay aligned on one backend
## Recommended Shape
- Run the MiroFish backend locally
- Run one MCP server against that backend
- Point Codex and Claude at the same MCP server
```text
Codex ----\
>---- MiroFish MCP ---- MiroFish backend
Claude ---/
```
## Start Order
From [`/Users/al/Documents/CODEX/MiroFish`](/Users/al/Documents/CODEX/MiroFish):
```bash
npm run backend
```
In another terminal:
```bash
npm run mcp:stdio
```
If you prefer HTTP transport instead of stdio:
```bash
MIROFISH_BASE_URL=http://127.0.0.1:5001 npm run mcp:http
```
## Codex Connection
Register the MCP server in Codex using the command below as the server command:
```bash
cd /Users/al/Documents/CODEX/MiroFish/backend && uv run python ../integrations/mcp/mirofish_mcp_server.py --transport stdio
```
Recommended environment:
```text
MIROFISH_BASE_URL=http://127.0.0.1:5001
MIROFISH_HTTP_TIMEOUT=60
```
Use stdio for local Codex work unless you specifically need HTTP transport for shared remote access.
## Claude Connection
Register the same MCP server command in Claude's MCP settings:
```bash
cd /Users/al/Documents/CODEX/MiroFish/backend && uv run python ../integrations/mcp/mirofish_mcp_server.py --transport stdio
```
Use the same environment values:
```text
MIROFISH_BASE_URL=http://127.0.0.1:5001
MIROFISH_HTTP_TIMEOUT=60
```
This keeps Codex and Claude on one shared tool surface and avoids separate wrapper logic.
## MCP Tools You Can Rely On
- `mirofish_health`
- `mirofish_list_projects`
- `mirofish_get_project`
- `mirofish_build_graph`
- `mirofish_get_graph_task`
- `mirofish_create_simulation`
- `mirofish_prepare_simulation`
- `mirofish_prepare_status`
- `mirofish_start_simulation`
- `mirofish_stop_simulation`
- `mirofish_simulation_status`
- `mirofish_simulation_timeline`
- `mirofish_interview_agents`
- `mirofish_generate_report`
- `mirofish_report_status`
- `mirofish_get_report`
- `mirofish_get_report_by_simulation`
- `mirofish_chat_report`
## Recommended Operator Flow
1. Confirm backend health with `mirofish_health`.
2. Choose an existing project with `mirofish_list_projects`.
3. Build or rebuild the graph with `mirofish_build_graph`.
4. Poll graph completion with `mirofish_get_graph_task`.
5. Create a simulation with `mirofish_create_simulation`.
6. Prepare the simulation with `mirofish_prepare_simulation`.
7. Poll readiness with `mirofish_prepare_status`.
8. Start the run with `mirofish_start_simulation`.
9. Poll runtime with `mirofish_simulation_status`.
10. Generate the report with `mirofish_generate_report`.
11. Fetch the final output with `mirofish_get_report_by_simulation`.
12. Ask follow-up questions with `mirofish_chat_report`.
## Notes
- Real simulation runs still require valid `LLM_API_KEY` and `ZEP_API_KEY`.
- The MCP server is a control layer, not a replacement for the MiroFish backend.
- n8n should call the backend directly for scheduled runs unless you explicitly want agent-mediated orchestration.

127
docs/integration-stack.md Normal file
View File

@ -0,0 +1,127 @@
# MiroFish Integration Stack
## Goal
Use **MiroFish** as the prediction engine and simulation brain, with:
- **Codex** as the builder and operator
- **Claude** as the reasoning and synthesis layer
- **n8n** as the automation layer
- **MCP** as the shared tool access layer
## Recommended Architecture
```text
Codex / Claude
|
v
MCP tools
|
v
MiroFish backend API
|
+--> graph build
+--> simulation lifecycle
+--> interviews with agents
+--> report generation and chat
|
v
MiroFish frontend
n8n
|
+--> calls MiroFish backend directly over HTTP
+--> or invokes the same lifecycle through the MCP server
```
## Roles
### Codex
- builds workflow glue, prompts, and wrappers
- drives MiroFish through MCP tools
- prepares projects, simulations, and reports
### Claude
- consumes simulation outputs and reports
- performs deeper reasoning on what the simulation means
- uses the same MCP tools so it sees the same state as Codex
### n8n
- schedules or triggers prediction runs
- polls preparation/report task status
- routes outputs to Slack, email, dashboards, or databases
### MCP
- standardizes access to MiroFish
- gives Codex and Claude a stable tool layer
- avoids coupling every agent directly to raw REST details
## Added in This Setup
- MCP server: [`integrations/mcp/mirofish_mcp_server.py`](/Users/al/Documents/CODEX/MiroFish/integrations/mcp/mirofish_mcp_server.py)
- start scripts:
- [`scripts/start_mirofish_mcp_stdio.sh`](/Users/al/Documents/CODEX/MiroFish/scripts/start_mirofish_mcp_stdio.sh)
- [`scripts/start_mirofish_mcp_http.sh`](/Users/al/Documents/CODEX/MiroFish/scripts/start_mirofish_mcp_http.sh)
- Codex and Claude setup guide:
- [`docs/codex-claude-mcp-setup.md`](/Users/al/Documents/CODEX/MiroFish/docs/codex-claude-mcp-setup.md)
- n8n workflow template:
- [`integrations/n8n/mirofish_prediction_pipeline.json`](/Users/al/Documents/CODEX/MiroFish/integrations/n8n/mirofish_prediction_pipeline.json)
- npm scripts:
- `npm run mcp:stdio`
- `npm run mcp:http`
## MCP Tools Exposed
- health
- project list
- project detail
- graph build
- graph task status
- simulation create
- simulation prepare
- simulation prepare status
- simulation start
- simulation stop
- simulation run status
- simulation timeline
- batch interviews
- report generate
- report generate status
- report fetch
- report fetch by simulation
- report chat
## n8n Automation Pattern
Use HTTP Request nodes against the backend:
1. `POST /api/graph/build`
2. poll `GET /api/graph/task/{task_id}`
3. `POST /api/simulation/create`
4. `POST /api/simulation/prepare`
5. poll `POST /api/simulation/prepare/status`
6. `POST /api/simulation/start`
7. poll `GET /api/simulation/{simulation_id}/run-status`
8. `POST /api/report/generate`
9. poll `POST /api/report/generate/status`
10. `GET /api/report/by-simulation/{simulation_id}`
An importable starter workflow is included at
[`integrations/n8n/mirofish_prediction_pipeline.json`](/Users/al/Documents/CODEX/MiroFish/integrations/n8n/mirofish_prediction_pipeline.json).
## Suggested Operating Mode
- Let Codex build and evolve the simulation workflow.
- Let Claude reason over the generated report and interview outputs.
- Let n8n handle timed or event-driven execution.
- Treat MiroFish as the core prediction substrate, not the orchestration system.
## Notes
- Real simulation quality depends on valid `LLM_API_KEY` and `ZEP_API_KEY`.
- Local boot verification can use placeholder values, but real runs cannot.
- Python 3.12 is required for this repo on this Mac.

View File

@ -0,0 +1,213 @@
from __future__ import annotations
import argparse
import os
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
DEFAULT_BASE_URL = os.environ.get("MIROFISH_BASE_URL", "http://127.0.0.1:5001")
DEFAULT_TIMEOUT = float(os.environ.get("MIROFISH_HTTP_TIMEOUT", "60"))
mcp = FastMCP(
name="MiroFish MCP",
instructions=(
"Use these tools to drive MiroFish as a prediction engine and simulation brain. "
"Create a project graph first, then create a simulation, prepare it, start it, "
"and generate or fetch reports."
),
)
def _base_url() -> str:
return os.environ.get("MIROFISH_BASE_URL", DEFAULT_BASE_URL).rstrip("/")
def _request(method: str, path: str, *, params: dict[str, Any] | None = None, json_body: dict[str, Any] | None = None) -> dict[str, Any]:
url = f"{_base_url()}{path}"
with httpx.Client(timeout=DEFAULT_TIMEOUT) as client:
response = client.request(method, url, params=params, json=json_body)
response.raise_for_status()
content_type = response.headers.get("content-type", "")
if "application/json" in content_type:
return response.json()
return {"success": True, "status_code": response.status_code, "text": response.text}
@mcp.tool()
def mirofish_health() -> dict[str, Any]:
return _request("GET", "/health")
@mcp.tool()
def mirofish_list_projects() -> dict[str, Any]:
return _request("GET", "/api/graph/project/list")
@mcp.tool()
def mirofish_get_project(project_id: str) -> dict[str, Any]:
return _request("GET", f"/api/graph/project/{project_id}")
@mcp.tool()
def mirofish_build_graph(payload: dict[str, Any]) -> dict[str, Any]:
return _request("POST", "/api/graph/build", json_body=payload)
@mcp.tool()
def mirofish_get_graph_task(task_id: str) -> dict[str, Any]:
return _request("GET", f"/api/graph/task/{task_id}")
@mcp.tool()
def mirofish_create_simulation(
project_id: str,
graph_id: str | None = None,
enable_twitter: bool = True,
enable_reddit: bool = True,
) -> dict[str, Any]:
payload = {
"project_id": project_id,
"enable_twitter": enable_twitter,
"enable_reddit": enable_reddit,
}
if graph_id:
payload["graph_id"] = graph_id
return _request("POST", "/api/simulation/create", json_body=payload)
@mcp.tool()
def mirofish_prepare_simulation(
simulation_id: str,
entity_types: list[str] | None = None,
use_llm_for_profiles: bool = True,
parallel_profile_count: int = 5,
force_regenerate: bool = False,
) -> dict[str, Any]:
payload: dict[str, Any] = {
"simulation_id": simulation_id,
"use_llm_for_profiles": use_llm_for_profiles,
"parallel_profile_count": parallel_profile_count,
"force_regenerate": force_regenerate,
}
if entity_types:
payload["entity_types"] = entity_types
return _request("POST", "/api/simulation/prepare", json_body=payload)
@mcp.tool()
def mirofish_prepare_status(task_id: str) -> dict[str, Any]:
return _request("POST", "/api/simulation/prepare/status", json_body={"task_id": task_id})
@mcp.tool()
def mirofish_start_simulation(
simulation_id: str,
platform: str = "parallel",
max_rounds: int | None = None,
enable_graph_memory_update: bool = False,
force: bool = False,
) -> dict[str, Any]:
payload: dict[str, Any] = {
"simulation_id": simulation_id,
"platform": platform,
"enable_graph_memory_update": enable_graph_memory_update,
"force": force,
}
if max_rounds is not None:
payload["max_rounds"] = max_rounds
return _request("POST", "/api/simulation/start", json_body=payload)
@mcp.tool()
def mirofish_stop_simulation(simulation_id: str) -> dict[str, Any]:
return _request("POST", "/api/simulation/stop", json_body={"simulation_id": simulation_id})
@mcp.tool()
def mirofish_simulation_status(simulation_id: str, detailed: bool = False) -> dict[str, Any]:
suffix = "/run-status/detail" if detailed else "/run-status"
return _request("GET", f"/api/simulation/{simulation_id}{suffix}")
@mcp.tool()
def mirofish_simulation_timeline(simulation_id: str) -> dict[str, Any]:
return _request("GET", f"/api/simulation/{simulation_id}/timeline")
@mcp.tool()
def mirofish_interview_agents(
simulation_id: str,
interviews: list[dict[str, Any]],
platform: str = "parallel",
) -> dict[str, Any]:
return _request(
"POST",
"/api/simulation/interview/batch",
json_body={
"simulation_id": simulation_id,
"platform": platform,
"interviews": interviews,
},
)
@mcp.tool()
def mirofish_generate_report(simulation_id: str, force_regenerate: bool = False) -> dict[str, Any]:
return _request(
"POST",
"/api/report/generate",
json_body={"simulation_id": simulation_id, "force_regenerate": force_regenerate},
)
@mcp.tool()
def mirofish_report_status(task_id: str) -> dict[str, Any]:
return _request("POST", "/api/report/generate/status", json_body={"task_id": task_id})
@mcp.tool()
def mirofish_get_report(report_id: str) -> dict[str, Any]:
return _request("GET", f"/api/report/{report_id}")
@mcp.tool()
def mirofish_get_report_by_simulation(simulation_id: str) -> dict[str, Any]:
return _request("GET", f"/api/report/by-simulation/{simulation_id}")
@mcp.tool()
def mirofish_chat_report(
simulation_id: str,
message: str,
chat_history: list[dict[str, str]] | None = None,
) -> dict[str, Any]:
payload: dict[str, Any] = {
"simulation_id": simulation_id,
"message": message,
}
if chat_history:
payload["chat_history"] = chat_history
return _request("POST", "/api/report/chat", json_body=payload)
def main() -> None:
parser = argparse.ArgumentParser(description="Expose MiroFish backend APIs over MCP.")
parser.add_argument("--transport", choices=["stdio", "http"], default="stdio")
parser.add_argument("--host", default=os.environ.get("MIROFISH_MCP_HOST", "127.0.0.1"))
parser.add_argument("--port", type=int, default=int(os.environ.get("MIROFISH_MCP_PORT", "8000")))
args = parser.parse_args()
if args.transport == "http":
mcp.settings.host = args.host
mcp.settings.port = args.port
mcp.run(transport="streamable-http")
return
mcp.run()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,650 @@
{
"name": "MiroFish Prediction Pipeline",
"nodes": [
{
"parameters": {},
"id": "manual-trigger",
"name": "Manual Trigger",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
-1360,
160
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "mirofish-base-url",
"name": "mirofishBaseUrl",
"value": "http://127.0.0.1:5001",
"type": "string"
},
{
"id": "project-id",
"name": "projectId",
"value": "proj_replace_me",
"type": "string"
},
{
"id": "graph-name",
"name": "graphName",
"value": "Prediction Brain Graph",
"type": "string"
},
{
"id": "chunk-size",
"name": "chunkSize",
"value": 500,
"type": "number"
},
{
"id": "chunk-overlap",
"name": "chunkOverlap",
"value": 50,
"type": "number"
},
{
"id": "enable-twitter",
"name": "enableTwitter",
"value": true,
"type": "boolean"
},
{
"id": "enable-reddit",
"name": "enableReddit",
"value": true,
"type": "boolean"
},
{
"id": "use-llm-profiles",
"name": "useLlmForProfiles",
"value": true,
"type": "boolean"
},
{
"id": "parallel-profile-count",
"name": "parallelProfileCount",
"value": 5,
"type": "number"
},
{
"id": "max-rounds",
"name": "maxRounds",
"value": 24,
"type": "number"
}
]
},
"options": {}
},
"id": "set-inputs",
"name": "Set Inputs",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-1140,
160
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $json.mirofishBaseUrl + '/api/graph/build' }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { project_id: $json.projectId, graph_name: $json.graphName, chunk_size: $json.chunkSize, chunk_overlap: $json.chunkOverlap } }}",
"options": {}
},
"id": "build-graph",
"name": "Build Graph",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-920,
160
]
},
{
"parameters": {
"method": "GET",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/graph/task/' + $json.data.task_id }}",
"options": {}
},
"id": "poll-graph-task",
"name": "Poll Graph Task",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-700,
160
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.data.status }}",
"operation": "equal",
"value2": "completed"
}
]
}
},
"id": "graph-complete",
"name": "Graph Complete?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-480,
160
]
},
{
"parameters": {
"amount": 20,
"unit": "seconds"
},
"id": "wait-graph",
"name": "Wait Graph",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
-480,
320
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/simulation/create' }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { project_id: $('Set Inputs').item.json.projectId, enable_twitter: $('Set Inputs').item.json.enableTwitter, enable_reddit: $('Set Inputs').item.json.enableReddit } }}",
"options": {}
},
"id": "create-simulation",
"name": "Create Simulation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-260,
80
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/simulation/prepare' }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { simulation_id: $json.data.simulation_id, use_llm_for_profiles: $('Set Inputs').item.json.useLlmForProfiles, parallel_profile_count: $('Set Inputs').item.json.parallelProfileCount } }}",
"options": {}
},
"id": "prepare-simulation",
"name": "Prepare Simulation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-40,
80
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/simulation/prepare/status' }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { task_id: $json.data.task_id } }}",
"options": {}
},
"id": "poll-prepare-status",
"name": "Poll Prepare Status",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
180,
80
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.data.status }}",
"operation": "equal",
"value2": "ready"
}
]
}
},
"id": "prepare-ready",
"name": "Prepare Ready?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
400,
80
]
},
{
"parameters": {
"amount": 30,
"unit": "seconds"
},
"id": "wait-prepare",
"name": "Wait Prepare",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
400,
240
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/simulation/start' }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { simulation_id: $('Create Simulation').item.json.data.simulation_id, platform: 'parallel', max_rounds: $('Set Inputs').item.json.maxRounds, enable_graph_memory_update: false, force: false } }}",
"options": {}
},
"id": "start-simulation",
"name": "Start Simulation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
620,
0
]
},
{
"parameters": {
"method": "GET",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/simulation/' + $('Create Simulation').item.json.data.simulation_id + '/run-status' }}",
"options": {}
},
"id": "poll-run-status",
"name": "Poll Run Status",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
840,
0
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.data.status }}",
"operation": "equal",
"value2": "completed"
}
]
}
},
"id": "simulation-complete",
"name": "Simulation Complete?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1060,
0
]
},
{
"parameters": {
"amount": 60,
"unit": "seconds"
},
"id": "wait-simulation",
"name": "Wait Simulation",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1060,
160
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/report/generate' }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { simulation_id: $('Create Simulation').item.json.data.simulation_id, force_regenerate: false } }}",
"options": {}
},
"id": "generate-report",
"name": "Generate Report",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1280,
-80
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/report/generate/status' }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { task_id: $json.data.task_id } }}",
"options": {}
},
"id": "poll-report-status",
"name": "Poll Report Status",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1500,
-80
]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.data.status }}",
"operation": "equal",
"value2": "completed"
}
]
}
},
"id": "report-complete",
"name": "Report Complete?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1720,
-80
]
},
{
"parameters": {
"amount": 30,
"unit": "seconds"
},
"id": "wait-report",
"name": "Wait Report",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1720,
80
]
},
{
"parameters": {
"method": "GET",
"url": "={{ $('Set Inputs').item.json.mirofishBaseUrl + '/api/report/by-simulation/' + $('Create Simulation').item.json.data.simulation_id }}",
"options": {}
},
"id": "fetch-report",
"name": "Fetch Report",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1940,
-160
]
}
],
"connections": {
"Manual Trigger": {
"main": [
[
{
"node": "Set Inputs",
"type": "main",
"index": 0
}
]
]
},
"Set Inputs": {
"main": [
[
{
"node": "Build Graph",
"type": "main",
"index": 0
}
]
]
},
"Build Graph": {
"main": [
[
{
"node": "Poll Graph Task",
"type": "main",
"index": 0
}
]
]
},
"Poll Graph Task": {
"main": [
[
{
"node": "Graph Complete?",
"type": "main",
"index": 0
}
]
]
},
"Graph Complete?": {
"main": [
[
{
"node": "Create Simulation",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait Graph",
"type": "main",
"index": 0
}
]
]
},
"Wait Graph": {
"main": [
[
{
"node": "Poll Graph Task",
"type": "main",
"index": 0
}
]
]
},
"Create Simulation": {
"main": [
[
{
"node": "Prepare Simulation",
"type": "main",
"index": 0
}
]
]
},
"Prepare Simulation": {
"main": [
[
{
"node": "Poll Prepare Status",
"type": "main",
"index": 0
}
]
]
},
"Poll Prepare Status": {
"main": [
[
{
"node": "Prepare Ready?",
"type": "main",
"index": 0
}
]
]
},
"Prepare Ready?": {
"main": [
[
{
"node": "Start Simulation",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait Prepare",
"type": "main",
"index": 0
}
]
]
},
"Wait Prepare": {
"main": [
[
{
"node": "Poll Prepare Status",
"type": "main",
"index": 0
}
]
]
},
"Start Simulation": {
"main": [
[
{
"node": "Poll Run Status",
"type": "main",
"index": 0
}
]
]
},
"Poll Run Status": {
"main": [
[
{
"node": "Simulation Complete?",
"type": "main",
"index": 0
}
]
]
},
"Simulation Complete?": {
"main": [
[
{
"node": "Generate Report",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait Simulation",
"type": "main",
"index": 0
}
]
]
},
"Wait Simulation": {
"main": [
[
{
"node": "Poll Run Status",
"type": "main",
"index": 0
}
]
]
},
"Generate Report": {
"main": [
[
{
"node": "Poll Report Status",
"type": "main",
"index": 0
}
]
]
},
"Poll Report Status": {
"main": [
[
{
"node": "Report Complete?",
"type": "main",
"index": 0
}
]
]
},
"Report Complete?": {
"main": [
[
{
"node": "Fetch Report",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait Report",
"type": "main",
"index": 0
}
]
]
},
"Wait Report": {
"main": [
[
{
"node": "Poll Report Status",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": false
},
"versionId": "1"
}

View File

@ -8,6 +8,8 @@
"setup:all": "npm run setup && npm run setup:backend",
"dev": "concurrently --kill-others -n \"backend,frontend\" -c \"green,cyan\" \"npm run backend\" \"npm run frontend\"",
"backend": "cd backend && uv run python run.py",
"mcp:stdio": "cd backend && uv run python ../integrations/mcp/mirofish_mcp_server.py --transport stdio",
"mcp:http": "cd backend && uv run python ../integrations/mcp/mirofish_mcp_server.py --transport http",
"frontend": "cd frontend && npm run dev",
"build": "cd frontend && npm run build"
},

View File

@ -0,0 +1,4 @@
#!/bin/sh
set -eu
cd /Users/al/Documents/CODEX/MiroFish/backend
uv run python ../integrations/mcp/mirofish_mcp_server.py --transport http

View File

@ -0,0 +1,4 @@
#!/bin/sh
set -eu
cd /Users/al/Documents/CODEX/MiroFish/backend
uv run python ../integrations/mcp/mirofish_mcp_server.py --transport stdio