Python (fastmcp Client)¶
For programmatic use — automation, ETL, internal AI agents — drive the MCP server from Python with fastmcp's client.
pip install "fastmcp>=2.11.3"
Hello-world¶
import asyncio
import json
from fastmcp import Client
from fastmcp.client.auth import BearerAuth
async def main():
url = "https://mcp.chordia.ai/mcp"
api_key = "YOUR_APPLICATION_KEY"
async with Client(url, auth=BearerAuth(api_key)) as client:
# Discover tools
tools = await client.list_tools()
print(f"server has {len(tools)} tools")
# Call one
result = await client.call_tool("get_project_summary", {})
data = json.loads(result.content[0].text)
print(f"total_calls={data['total_calls']} agent_count={data['agent_count']}")
asyncio.run(main())
Recommended sequence¶
For an LLM agent doing analytics work:
get_project_contextwith no arguments — pulls the client orientation (agent roster, signal frequencies, drivers). The LLM uses this to understand what the project actually contains.search_callsto list candidates matching the user's question (date range, agent, score band, lift band).get_call_detailwithsession_idfrom step 2 to drill into one call's transcript and full evaluation.query_interactionsas escape hatch — accepts a guarded MongoDB aggregation pipeline for anything the structured tools can't compose.
Listing resources¶
templates = await client.list_resource_templates()
for t in templates:
print(t.uriTemplate)
# → chordia://project/{project_id}/signals
# → chordia://project/{project_id}/guidance
# → chordia://call/{session_id}/transcript
Error shape¶
Every tool returns JSON via result.content[0].text. Errors are wrapped:
{ "error": "..." }
Patterns to handle:
"Authentication required. Pass your API key …"— bearer token missing or malformed"Invalid or inactive API key"— key was revoked or never existed"Call not found: <session_id>"— either the session genuinely doesn't exist OR the caller'sallowed_agentsscope doesn't include the session's owner (intentionally indistinguishable to prevent enumeration)"Access denied: user activity queries require Admin or SuperAdmin role"— tool requires admin role; mint a key withroles: ["Admin"]
Worked example¶
There's an end-to-end demo in the repo at
scripts/demo_mcp_rbac.py
that seeds a project + 4 calls + 3 keys (admin/supervisor/agent) and
runs the same tool set through each one to verify RBAC scoping live.
Useful as a reference for the call sequence.