Tutorial: Agent + Weather MCP
This tutorial builds a working weather assistant from two pieces you have already met: an MCP server with a weather tool, and an Agent that knows how to call it. The point is not the weather itself — it is the pattern. The same shape works for any controlled tool you want an agent to use safely.
What you are building
weather-tools— an MCP server that exposes a weather lookup tool.weather-agent— the agent that calls the tool and answers the user.
By the end, you can ask the agent for a city's conditions and get the answer through MCP instead of a guess.
Before you begin
- An account with project admin, or a project member working with your administrator.
platformctl, signed in.- The weather tool from Publish tools or the weather tutorial.
Step 1: Publish the weather tool
- platformctl
- curl
- Console
platformctl mcp create weather-tools
platformctl mcp tools set weather-tools get_forecast \
--handler @get_forecast.py \
--description "Current weather for a city"
curl -s -X POST "$CAI_API/v1/projects/$PROJ/mcpservers" \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d '{"name":"weather-tools","expose":""}'
jq -n --rawfile handler get_forecast.py \
'{handler: $handler, description: "Current weather for a city"}' |
curl -s -X PUT "$CAI_API/v1/projects/$PROJ/mcpservers/weather-tools/tools/get_forecast" \
-H "Authorization: Bearer ***" \
-H 'Content-Type: application/json' \
-d @-
- Open Compute → MCP servers.
- Create
weather-tools. - Publish the
get_forecasttool.
Step 2: Confirm the server is ready
Read the server back until the response is ready: true and you have an endpoint URL.
- platformctl
- curl
- Console
platformctl mcp get weather-tools
curl -s "$CAI_API/v1/projects/$PROJ/mcpservers/weather-tools" \
-H "Authorization: Bearer ***" | jq '.mcp_server | {state, ready, url, version, tool_names}'
The server page should show ready true and list get_forecast.
Step 3: Call the tool directly once
Before wiring the agent, prove the tool works from curl. This gives you a baseline that is independent of the model.
curl -s -X POST "$MCP_URL" \
-H "Authorization: Bearer $MCP_BEARER" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_forecast","arguments":{"city":"Reykjavik"}}}'
You should see a JSON-RPC result with the forecast object. If this fails, fix the MCP side first — the agent will only inherit that failure.
Step 4: Wire the agent to the MCP server
Write an agent that prefers the tool when the question is about weather. Keep the instruction narrow so the model chooses the tool quickly instead of reasoning around it.
- ADK
- LangGraph
- CrewAI
from google.adk.agents import Agent
from crusoe_adk.foundry import foundry_model
from crusoe_adk.mcp import mcp_toolsets
from crusoe_adk.tools import run_python
root_agent = Agent(
name="weather_agent",
model=foundry_model(),
instruction=("Use tools when asked for current weather. "
"Prefer MCP tool results over guessing."),
tools=[run_python, *mcp_toolsets()],
)
import asyncio
from langgraph.prebuilt import create_react_agent
import crusoe_langchain as crusoe
_tools = asyncio.run(crusoe.mcp_tools())
graph = create_react_agent(
crusoe.foundry_model(),
tools=[crusoe.run_python, *_tools],
prompt=("Use tools when asked for current weather. "
"Prefer MCP tool results over guessing."),
)
from crewai import Agent, Crew, Process, Task
import crusoe_crewai as crusoe
assistant = Agent(
role="Weather Assistant",
goal="Use the weather MCP tool when the question needs current conditions.",
backstory="A concise assistant with MCP access.",
llm=crusoe.foundry_model(),
tools=[crusoe.RunPython()] + crusoe.mcp_tools(),
verbose=False,
)
respond = Task(
description=(
"Prior conversation (may be empty on the first turn):\n{history}\n\n"
"Now answer the user's current message. Call get_forecast for current "
"weather rather than guessing:\n{message}"
),
expected_output="A short weather answer taken from the tool's output.",
agent=assistant,
)
crew = Crew(
agents=[assistant],
tasks=[respond],
process=Process.sequential,
)
A task description must reference {message}. That placeholder is the only route the user's message has into your crew: the platform fills it in on every turn. A crew with no task, or a task that never mentions {message}, is never handed the question. Reference {history} as well and the platform replays earlier turns into it.
Step 5: Ask the agent
Send the question and check two things:
- the agent chose the MCP tool,
- the answer reflects the tool's response rather than an invented forecast.
What success looks like
A working run usually looks like this:
- tool call selected,
get_forecastinvoked,- a concise answer that matches the tool result.
Common failures
- Tool not ready. The server is still
buildingordeploying. - Wrong secret handling. The weather tool's credential key was declared but the project secret value was never set.
- Model guessing instead of tool use. The instruction needs to be narrower, or the tool set is not attached.
Next steps
Go deeper
These advanced guides pick up where the quickstarts stop, each exercising a different slice of the platform:
| Guide | Framework / language |
|---|---|
| Multi-step research agent | LangGraph |
| Editorial pipeline with a crew | CrewAI |
| Support agent over your own docs | ADK |
| Document ingestion pipeline | Python |
| Webhook fan-out, exactly once | Node.js |
| Scheduled reconciliation job | Go |
| Object-store ETL with move-after-read | Ruby |