# Architecture — grafeo-mcp

## High-Level Design

```text
MCP Client (Claude, Copilot, VS Code, ...)
    │
    │  stdio / streamable-http
    ▼
┌─────────────────────────────────────┐
│  grafeo-mcp (FastMCP)               │
│                                     │
│  ┌──────────┐ ┌──────────────────┐  │
│  │  Tools    │ │ Resources        │  │
│  │  (14)     │ │ (graph:// URIs)  │  │
│  └────┬──────┘ └──────┬──────────┘  │
│       │               │             │
│  ┌────┴───────────────┴──────────┐  │
│  │     AppContext.db              │  │
│  │     (GrafeoDB instance)       │  │
│  └───────────────────────────────┘  │
│                                     │
│  ┌──────────────────────────────┐   │
│  │  Prompts (4 workflows)       │   │
│  └──────────────────────────────┘   │
└─────────────────────────────────────┘
```

## Lifecycle

1. **Startup** — `app_lifespan()` opens (or creates) a GrafeoDB instance based on `GRAFEO_DB_PATH`.
2. **Request handling** — MCP SDK dispatches tool calls, resource reads, and prompt requests to decorated handlers.
3. **Shutdown** — lifespan context manager closes the database cleanly.

## Agent Interaction Patterns

### Schema-first

Agents should always call `graph_info` first to understand labels, edge types, and
properties before writing queries. This prevents guessing at label names.

### Explore-then-query

Use `get_neighbors` for interactive exploration (one hop at a time).
Use `execute_gql` for precise multi-hop pattern queries.

### Vector seed + graph expand

Use `vector_graph_search` for the most context-rich results — it combines
semantic similarity with graph expansion in a single call.

### Tool disambiguation

Every tool docstring includes "Use this when..." / "Do NOT use for..." lines
so agents pick the right tool without trial-and-error.

## Module Responsibilities

### server.py

- Defines `AppContext` dataclass holding the `GrafeoDB` instance.
- `app_lifespan()` async context manager handles DB open/close.
- Creates the `FastMCP` instance (`mcp`) used by all other modules.
- `main()` entry point selects transport from CLI arg.

### tools/

Each module registers tools on the shared `mcp` instance via `@mcp.tool()`.

| Module        | Tools                                                                                                    | Purpose                          |
| ------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------- |
| query.py      | `execute_gql`                                                                                            | Run graph queries (GQL)          |
| graph.py      | `create_node`, `create_edge`, `get_node`, `get_neighbors`, `search_nodes_by_label`, `graph_info`         | CRUD + traversal + introspection |
| vector.py     | `vector_search`, `mmr_search`, `create_vector_index`, `vector_graph_search`                              | Embedding similarity + hybrid    |
| algorithms.py | `pagerank`, `dijkstra`, `louvain`, `betweenness_centrality`, `connected_components`                      | Graph analytics                  |

### resources/

Read-only data exposed via `graph://` URIs.

| Module    | URIs                               | Purpose                              |
| --------- | ---------------------------------- | ------------------------------------ |
| schema.py | `graph://schema`, `graph://stats`  | Rich schema overview, DB statistics  |
| nodes.py  | `graph://nodes/{node_id}`          | Node details + connection summary    |

### prompts/

Workflow orchestrator prompts that guide agents through multi-step tool sequences.

| Prompt                 | Purpose                                                      |
| ---------------------- | ------------------------------------------------------------ |
| `explore_graph`        | Schema discovery, sample nodes, traverse, pattern queries    |
| `knowledge_extraction` | Analyze text, create nodes, create edges, verify             |
| `graph_analysis`       | Overview, communities, PageRank, hub exploration             |
| `similarity_search`    | Identify index, get vector, search, explore context          |

## Token Management

All list-returning tools have `limit` parameters and truncate results when they exceed
budgets. Truncation messages tell agents how to get more data (e.g. "Use LIMIT in your
query" or "Use offset=N for the next page").

Large vector properties (>32 elements) are stripped from node summaries to prevent
embedding arrays from consuming the context window.

## Error Recovery

Error returns suggest which tool to try next. Examples:

- "Query failed" -> Try `graph_info` to check available labels.
- "Node not found" -> Use `search_nodes_by_label` to find valid IDs.
- "Syntax error" -> Cypher syntax is auto-normalized, but check GQL docs.

## Transport Strategy

| Transport       | When                                                 |
| --------------- | ---------------------------------------------------- |
| stdio           | Local use: Claude Desktop, Claude Code, VS Code      |
| streamable-http | Remote/production: Copilot Studio, Azure AI Foundry  |

Same binary, transport selected by CLI argument.

## Design Principles

1. **Schema-first** — `graph_info` is the entry point for any interaction.
2. **Token-aware** — all tools limit and truncate results; no context window blowouts.
3. **Disambiguation** — every tool doc says when to use it and when not to.
4. **Error recovery** — error messages suggest which tool to try next.
5. **Flat arguments** — no nested dicts; explicit params with defaults.
6. **Helpful errors** — return error strings, never raise into the transport.
7. **Zero infrastructure** — GrafeoDB is embedded; the MCP server IS the database.
