Skip to content

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())

For an LLM agent doing analytics work:

  1. get_project_context with no arguments — pulls the client orientation (agent roster, signal frequencies, drivers). The LLM uses this to understand what the project actually contains.
  2. search_calls to list candidates matching the user's question (date range, agent, score band, lift band).
  3. get_call_detail with session_id from step 2 to drill into one call's transcript and full evaluation.
  4. query_interactions as 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's allowed_agents scope 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 with roles: ["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.