Skip to content

MCP Integration ​

Cognitive Companion treats the home as something an AI agent can safely operate. A built-in Model Context Protocol (MCP) server, built on the official MCP Python SDK, exposes 61 tools for AI agent integration: agents can discover system state, query sensor data, inspect enrollment, face calibration progress, and e-ink status, check person locations, review activity timelines and daily reports, explore semantic memory, read the unified signals feed, acknowledge behavioral signals with feedback, drive and analyze guided routine sessions, propose identity corrections, trigger rule executions, author new rules, and inspect plugin metadata. The same tools are shared with the Gemini Live voice companion for function calling during conversations.

This makes Cognitive Companion agent-native: household state has one governed, authenticated tool surface, and every agent, whether Claude Desktop, a custom orchestrator, or the internal voice companion, goes through it. There is no separate integration to audit per client, and tools stay in lockstep with the UI because both read the same service layer.

What is MCP? ​

The Model Context Protocol is an open standard for connecting AI models to external tools and data sources. It provides a structured way for AI agents to:

  • Discover available tools and their parameters
  • Execute tools with validated inputs
  • Receive structured responses

Cognitive Companion's MCP server allows external AI agents (Claude, GPT, custom agents) to interact with the senior care system as part of their tool-calling workflows.

MCP and BFF parity guarantee ​

MCP tools and BFF router endpoints share one service layer (design rule D6). Any data exposed to the Vue UI through a router is exposed to MCP by reading the same service function, never a parallel query. Consequences:

  • MCP tools contain no query logic of their own; they call service methods.
  • Import-linter contracts enforce that mcp/ may not import a repository directly.
  • When a service response envelope changes, both the router and the MCP tool reflect the change automatically.
  • Smoke tests in backend/tests/mcp/ assert that every registered tool name resolves to a callable.

Architecture ​

The MCP server is implemented using the official mcp Python SDK's FastMCP class. Tools are defined as decorated async functions with type hints that auto-generate JSON schemas. The server is mounted as an ASGI sub-application on FastAPI at /mcp, serving the standard MCP protocol via streamable HTTP transport.

A GeminiToolAdapter reads the same tool definitions and converts them to Gemini FunctionDeclaration format, so the voice companion can call tools during conversations without duplicating implementations.

Available Tools ​

ToolDescriptionParameters
get_roomsList all configured roomsNone
get_sensorsList sensorsroom_name, sensor_type (optional filters)
get_room_occupancyCurrent occupancy from presence sensorsroom_name (optional)
get_recent_imagesRecent camera images for a sensorsensor_id, limit
get_light_levelIlluminance from a HA sensorentity_id
get_signals_feedUnified caregiver signals feed (CTS signals plus rule alerts)source, severity_min, room_name, limit (optional)
get_event_logsRule execution event logsrule_name, status, limit (optional)
get_rulesConfigured automation rulesenabled_only (default true)
get_conversation_historyRecent conversation turnssession_id, limit (optional)
get_person_locationsCurrent location of all tracked membersNone
get_enrolled_personsHousehold members with face enrollment dataNone
get_roster_healthMembers with too few enrolled face photos, plus recurring visitors awaiting reviewNone
get_face_calibration_summaryFace calibration labeling progress per resident, walks, and visitor labels (read-only)None
get_person_sightingsCamera sighting history for a personperson_id, limit
get_person_activitiesRecent detected activities (eating, sleeping, etc.)person_id, activity_type, minutes
get_workflow_executionsRecent pipeline workflow executionsrule_name, status, limit (optional)
get_rule_pipelinePipeline step definitions for a rulerule_id
trigger_ruleManually trigger a rule's pipeline executionrule_id
get_eink_display_statusActive e-ink image state for one or all displayssensor_id (optional)
get_local_datetimeCurrent local date and time for the household's timezoneNone
get_weatherCurrent weather from Home AssistantNone
get_person_timelineChronological timeline of activities and sightings for a personperson_id, minutes (optional)
get_daily_reportEnd-of-day wellness report for one or all membersperson_id, report_date (optional)
get_open_sessionsCurrently open activity sessions (meals, bathroom, etc.)person_id, activity_type (optional)
submit_user_responseRecord user response to an interactive prompt stepexecution_id, step_id, action
get_recent_scene_objectsRecent object presence in a roomroom_id, since_minutes
get_scene_observationsSearch scene observations with vector similarityquery_text, room_id, limit (optional)
get_person_movementsMovement transitions for a person between roomsperson_id, semantic, since_minutes (optional)
get_room_trendRoom-level trend state from object presence dataroom_id, since_hours (optional)
search_similar_scenesVector search across scene embeddingsquery_embedding, room_id, limit (optional)
get_tracking_statusOverall CTS tracking status and active PH count(none)
get_person_locationCurrent location envelope for one person (with quality/staleness)person_id
get_recent_dementia_signalsRecent dementia signals for a person with signal envelopesperson_id, limit (optional)
acknowledge_dementia_signalAcknowledge a dementia signal, optionally with caregiver feedbacksignal_id, feedback (optional)
get_gait_trendGait speed trend envelope for a residentperson_id, days (default 56)
get_heatmapAggregated floor-plan heatmap bins for a person over a time rangeperson_id, start_time, end_time, start_minute, end_minute (optional)
list_keyframe_framesKeyframes grouped per physical source frame for identity reviewperson_id, camera_id, tag_reason, conflict_only, pending_review_only, limit, offset (all optional)
propose_identity_correctionPropose an observation-bounded identity correction segment for a PHph_id, observation_id, at (optional)
get_identity_correction_jobStatus of an identity correction jobrevision_id
get_active_guided_stepCurrent step of an active guided sessionsession_id
mark_guided_step_completePropose that the resident completed the current guided stepsession_id, step_ord, note (optional)
repeat_guided_stepRephrase and repeat the current guided stepsession_id
report_step_blockedRecord that the resident is stuck on the current stepsession_id, reason
request_caregiver_helpEscalate a guided session to the caregiversession_id, reason (optional)
record_resident_preferenceRecord a stable resident preference (not a transient fact) to the knowledge repositoryperson_id, preference, context (optional)
get_guided_completion_summaryGuided-task completion outcomesperson_id, routine_id, since, until (optional)
get_guided_attempts_per_stepRetry pressure by guided routine stepperson_id, routine_id, since, until (optional)
get_guided_time_to_completeGuided routine completion durationsperson_id, routine_id, since, until (optional)
get_guided_abandonmentGuided-task abandonment rate and reasonsperson_id, routine_id, since, until (optional)
get_guided_escalation_breakdownGuided-task escalation reasonsperson_id, routine_id, since, until (optional)
get_guided_vision_agreementGuided-task vision agreement qualityperson_id, routine_id, since, until (optional)
get_guided_time_of_dayGuided outcomes bucketed by local hourperson_id, routine_id, since, until (optional)
get_guided_watch_summaryGuided-task watch runs and agreementperson_id, routine_id, since, until (optional)
get_guided_gate_cost_summaryGuided-task vision gate execution costsperson_id, routine_id, since, until (optional)
query_knowledge_baseSemantic search over the knowledge repositoryquery
get_current_quiz_questionCurrent question in an active quiz sessionsession_id
submit_quiz_answerRecord an answer to a quiz questionsession_id, answer
complete_quiz_sessionClose a quiz sessionsession_id
list_rulesList all rules with summary info(none)
list_plugin_metadataMetadata for all registered steps, filters, and channelskind (optional: "step", "filter", "channel")
get_rule_bundleExport a rule as a portable bundlerule_id
import_rule_bundleValidate or commit a rule bundlebundle (RuleBundle dict), mode ("preview" or "commit")

Authentication ​

MCP tools require authentication via the API key. The key is configured in config/auth.yaml:

yaml
api_keys:
  - key: ${CC_MCP_API_KEY}
    name: mcp_agent
    permissions:
      - mcp_readonly

Pass the key in the X-API-Key header or an Authorization: Bearer <key> header. A key in the query string is rejected.

Every tool is listed to every authenticated agent, and each call is authorized against the token the tool requires:

ToolsTokenGranted to
All read toolsmcp.tools:readmcp_readonly, admin
import_rule_bundlerules:importrules:write_via_mcp (the shipped agent key), admin
trigger_rulerules:executeadmin
acknowledge_dementia_signalcts.signals:acknowledgeadmin
propose_identity_correctioncts.identity:proposeadmin
Resident session tools (quiz answers, guided steps, preferences, submit_user_response)resident_session:actno API key: these are for the built-in voice companion only

So the mcp_readonly key can read anything the read tools expose but cannot trigger a rule, acknowledge a signal, or act for the resident. To let an agent key call a state-changing tool, add that tool's token to the key's role in config/auth.yaml. A denied call returns HTTP 403 with a JSON-RPC error and never runs the tool; a batch containing one denied call is rejected whole.

Endpoint ​

The MCP server is available at a single endpoint:

MethodPathDescription
POST/mcpMCP protocol endpoint (streamable HTTP, JSON-RPC)

Tool Discovery ​

bash
curl -X POST \
  -H "X-API-Key: $CC_MCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \
  http://localhost:8000/mcp

Tool Execution ​

bash
curl -X POST \
  -H "X-API-Key: $CC_MCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_person_sightings","arguments":{"person_id":"grandma"}},"id":2}' \
  http://localhost:8000/mcp

Integration Patterns ​

With Claude Desktop ​

Configure Claude Desktop's MCP settings to point to your Cognitive Companion instance:

json
{
  "mcpServers": {
    "cognitive-companion": {
      "url": "http://your-cc-host:8000/mcp",
      "headers": {
        "X-API-Key": "your_mcp_key"
      }
    }
  }
}

With Custom Agents ​

Any agent framework that supports the MCP protocol can integrate with Cognitive Companion by pointing to the /mcp endpoint. The standard JSON-RPC interface handles tool discovery and execution.

Example Agent Workflow ​

An AI agent monitoring the household might:

  1. Call get_person_locations to check where everyone is
  2. Call get_enrolled_persons to see which household members are tracked
  3. Call get_person_activities to check if lunch has been eaten
  4. If lunch has not been detected, call trigger_rule on the lunch reminder rule
  5. Call get_signals_feed to check for any unacknowledged signals

Voice Companion Integration ​

A configurable subset of MCP tools is also available to the Gemini Live voice companion via function calling. When the senior asks a question like "what's the weather?" or "where is everyone?", Gemini pauses audio generation, calls the appropriate tool, and incorporates the result into its spoken response. Tool results are never displayed raw to the user; they always flow through Gemini's natural language audio response.

The voice-enabled tool subset is configured in settings.yaml:

yaml
mcp:
  gemini_tools:
    - "get_rooms"
    - "get_room_occupancy"
    - "get_person_locations"
    - "get_signals_feed"
    - "get_weather"
    - "get_recent_scene_objects"
    - "get_room_trend"
    - "get_person_movements"
    - "get_local_datetime"
    - "get_person_activities"
    - "get_enrolled_persons"
    - "get_person_timeline"
    - "get_daily_report"
    - "get_open_sessions"
    - "submit_user_response"
    - "query_knowledge_base"
    - "submit_quiz_answer"
    - "get_current_quiz_question"
    - "complete_quiz_session"
    - "get_active_guided_step"
    - "mark_guided_step_complete"
    - "repeat_guided_step"
    - "report_step_blocked"
    - "request_caregiver_help"
    - "record_resident_preference"

The voice agent can declare and call exactly the tools in mcp.gemini_tools, checked again when it calls one, and an empty list gives it no tools. Destructive tools like trigger_rule are not in the shipped list. The guided-session tools are voice-enabled by design: they are how the realtime agent proposes step completion, repeats a step, or escalates to a caregiver during a guided routine. get_person_timeline, get_daily_report, and get_open_sessions are the typed daily-living ledger tools: the agent answers countable questions ("has she had her medication today") by calling these, never by aggregating semantic-memory captions.

Network Considerations ​

The MCP server runs on the same backend instance, so no additional deployment is needed. Since Cognitive Companion runs on-premise without a public endpoint, MCP clients must be on the same local network. For remote agent access, consider:

  • VPN or tailnet for secure remote access
  • A reverse proxy with authentication for controlled exposure

Adding New Tools ​

  1. Add a @_register(token=...) decorated async function in backend/mcp/server.py. Type hints on parameters auto-generate JSON schemas. The token is required: TOOLS_READ for a read tool, or a new <resource>:<action> token (defined in config/auth.yaml) for a tool that changes state.
  2. If the tool should be available in voice conversations, add it to mcp.gemini_tools in config/settings.yaml.

See the development guide for more details.

Released under the AGPL-3.0 License.