Give an AI agent controlled access to real laboratory operations with FlaskTrack's organization-scoped MCP tool interface.
In this walkthrough, you will create a small Python agent that discovers FlaskTrack tools, searches laboratory records, executes a tool, and uses structured results to continue safely.
Dynamic tool discovery Read the live MCP registry instead of hard-coding the API surface
Typed laboratory records Work with workflows, protocols, batches, samples, species, and more
Organization scoped Every action is evaluated in the authenticated FlaskTrack organization
Permission aware Agent calls remain subject to roles, validation, and compliance controls
Structured results Use returned record IDs and metadata to safely continue multi-step work
What you are building #
The agent will discover the tools exposed by your FlaskTrack deployment, choose a read operation, execute it through the MCP interface, and use the structured result as context for the next decision.
Discover tools Load the current FlaskTrack tool catalog from
/mcp/tools
.Choose a tool Give the model names, descriptions, schemas, and semantic record metadata.
Execute through FlaskTrack Send one registered tool name and schema-valid input to
/mcp/call
.Continue from the result Use the concrete returned record ID instead of guessing or inventing identifiers.
Before you start #
Create a FlaskTrack API credential for the integration and keep it outside your prompt, source code, browser JavaScript, and model context.
API key Use a dedicated machine credential for the agent.
Organization Every request includes the FlaskTrack organization context.
Python 3.10+ The example uses Python,
requests
, and any model client you prefer.LLM provider OpenAI, Anthropic, a local model, or another provider can drive the decision loop.
Configure FlaskTrack credentials #
Keep credentials in environment variables so the model never sees them.
export FLASKTRACK_URL="https://flasktrack.com"
export FLASKTRACK_ORGANIZATION="YOUR_ORGANIZATION_ID"
export FLASKTRACK_API_KEY="YOUR_API_KEY"
Install the tiny client #
python -m pip install requests
Connect to FlaskTrack #
Keep credentials in the HTTP layer rather than the prompt.
import os
import requests
BASE_URL = os.environ["FLASKTRACK_URL"].rstrip("/")
HEADERS = {
"x-organization": os.environ["FLASKTRACK_ORGANIZATION"],
"x-api-key": os.environ["FLASKTRACK_API_KEY"],
"accept": "application/json",
}
def flasktrack_get(path):
response = requests.get(
f"{BASE_URL}{path}",
headers=HEADERS,
timeout=30,
)
response.raise_for_status()
return response.json()
def flasktrack_post(path, payload):
response = requests.post(
f"{BASE_URL}{path}",
headers={**HEADERS, "content-type": "application/json"},
json=payload,
timeout=60,
)
response.raise_for_status()
return response.json()
Discover the live MCP tool catalog #
Do not hard-code every FlaskTrack action. Ask the running deployment what tools are currently registered.
tools = flasktrack_get("/mcp/tools")
for tool in tools:
print(
tool["name"],
tool["effect"],
tool.get("output_entity"),
)
Why discovery matters FlaskTrack's tool surface evolves with the platform. Runtime discovery lets an agent adapt to the deployed version instead of relying on a stale list copied into a prompt.
Give the model a compact tool list #
def compact_tools(tools):
return [
{
"name": tool["name"],
"description": tool["description"],
"effect": tool["effect"],
"input_schema": tool["input_schema"],
"entity_fields": tool.get("entity_fields", []),
"output_entity": tool.get("output_entity"),
}
for tool in tools
]
agent_tools = compact_tools(tools)
Keep authentication headers, API keys, cookies, and unrelated organization data outside model-visible context.
Ask the model for one tool call #
Keep the first agent intentionally simple: the model returns one registered tool name and one JSON input object.
import json
SYSTEM_PROMPT = """
You are a FlaskTrack laboratory assistant.
Choose exactly one FlaskTrack tool for the user's request.
Rules:
- Use only tool names supplied to you.
- Match the tool input schema exactly.
- Never invent FlaskTrack UUIDs.
- Treat Workflow, Protocol, Batch, Sample, Species, Tool,
Ingredient, Plasmid, and other entity IDs as distinct types.
- Prefer read tools when you still need to identify a record.
- Return JSON only:
{
"name": "tool_name",
"input": {}
}
"""
def choose_tool(llm, user_request, tools):
raw = llm(
system=SYSTEM_PROMPT,
user=json.dumps({
"request": user_request,
"tools": tools,
}),
)
return json.loads(raw)
The llm
function is provider-agnostic. Wrap your preferred model SDK and make it return the model's text response.
Execute the selected FlaskTrack tool #
def call_tool(tool_call):
return flasktrack_post(
"/mcp/call",
{
"name": tool_call["name"],
"input": tool_call["input"],
},
)
FlaskTrack resolves the registered tool and applies its normal input validation, organization scope, permissions, route, and operation semantics.
Put the pieces together #
def run_agent_once(llm, request):
tools = flasktrack_get("/mcp/tools")
tool_call = choose_tool(
llm,
request,
compact_tools(tools),
)
print("Selected tool:", tool_call["name"])
print("Input:", json.dumps(tool_call["input"], indent=2))
result = call_tool(tool_call)
print("Result:")
print(json.dumps(result, indent=2))
return result
run_agent_once(
llm,
"Find the workflow used for banana multiplication.",
)
That is the core FlaskTrack agent loop: discover, decide, execute, inspect.
Use real results for multi-step work #
If one action creates a record needed by the next action, use the concrete ID returned by FlaskTrack.
workflow = call_tool({
"name": "create_workflow",
"input": workflow_input,
})
workflow_id = workflow["result"]["primary_id"]
batch = call_tool({
"name": "create_batch",
"input": {
"name": "Agent-created batch",
"workflow_id": workflow_id,
"species_id": species_id,
"planned_quantity": 24,
},
})
Never invent future IDs Do not use strings such as
workflow_id_placeholder
. Execute the first operation, capture its authoritative result, and use that value in the next direct MCP call.
Optional: preview a mutation before execution #
Use /mcp/prepare
when your integration wants a validation or review step before direct execution.
def prepare_tool(tool_call):
return flasktrack_post(
"/mcp/prepare",
{
"name": tool_call["name"],
"input": tool_call["input"],
},
)
Preparation does not execute the underlying operation. Use it for policy checks, logging, or a human confirmation surface.
Three rules that make agents dramatically safer #
Search before mutation If the agent does not know an exact record, use a FlaskTrack read tool first.
Respect entity types A Protocol UUID is not a Workflow UUID. Use the semantic type declared by the tool.
Stop on control failures Authorization, compliance, validation, and signature failures are authoritative. Do not route around them.
From demo agent to production integration #
- ✔ Use a dedicated FlaskTrack service identity and minimum required permissions
- ✔ Keep API keys outside model-visible context
- ✔ Discover tools from the target deployment at runtime
- ✔ Use read tools to resolve exact records before mutation
- ✔ Validate typed entity relationships rather than accepting arbitrary UUIDs
- ✔ Add explicit human approval for high-impact or mutating operations
- ✔ Use bounded retries and timeouts
- ✔ Preserve idempotency keys where supported or required
- ✔ Log tool names, correlation IDs, statuses, and returned record IDs without secrets
- ✔ Treat electronic-signature and compliance controls as server-authoritative
Build the agent around your laboratory #
Start with one read workflow, add one reviewed mutation, and expand only after the integration behaves predictably against real FlaskTrack records.
Start read-only
Begin with discovery, workflow lookup, batch status, or reporting before enabling mutation tools.
Add approval
Put a human or policy gate in front of creation, updates, completion, and other operational actions.
Expand deliberately
Add tools as the agent proves reliable rather than exposing every available mutation on day one.
Your agent can now operate on the same laboratory model as your team #
Full Biolab Integrated MCP Agent Example On Github
FlaskTrack gives agents a structured, permission-aware interface to laboratory records and operations without browser automation, direct database access, or a separate shadow data model.