Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*
!harper-best-practices/**/*
!harper-mcp/**/*
!dist/**/*
!AGENTS.md
!LICENSE
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ This repository contains "skills" that guide AI agents in developing Harper appl
## Available Skills

- [Harper Best Practices](harper-best-practices/SKILL.md): Comprehensive guidelines for building, extending, and deploying Harper applications.
- [Harper MCP](harper-mcp/SKILL.md): Comprehensive guide to Harper's Model Context Protocol (MCP) interface — server setup, tools, prompts, resources, rate limiting, quotas, and security.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ Comprehensive guidelines for building, extending, and deploying Harper applicati
- Custom resources and table extensions.
- Advanced features like Vector Indexing and Caching.

### [Harper MCP](harper-mcp/SKILL.md)

Comprehensive guide to Harper's Model Context Protocol (MCP) interface. Covers:

- Enabling the MCP server profiles and connecting AI clients.
- Automatic CRUD verb tools and custom `mcpTools` / `mcpPrompts` / `mcpResources`.
- The resources surface (`harper://`, `harper+rest://`, custom URIs and templates).
- Rate limiting, durable quotas, and the security model for public endpoints.

## How it Works

These skills are structured to be easily consumed by Large Language Models (LLMs) and AI agents. For a technical overview of how agents use these files, see [AGENTS.md](AGENTS.md).
510 changes: 510 additions & 0 deletions harper-mcp/AGENTS.md

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions harper-mcp/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
name: harper-mcp
description: Comprehensive guide to Harper's Model Context Protocol (MCP) interface,
covering server setup, client connection, automatic and custom tools, prompts,
resources, rate limiting, durable quotas, and the security model.
Triggers on tasks involving MCP servers on Harper, AI-client integration,
and exposing Harper data or behavior to LLM agents.
license: Apache-2.0
metadata:
author: harper
version: '1.0.0'
---

# Harper MCP

Guidelines for exposing a Harper instance as a Model Context Protocol (MCP) server and for building the tools, prompts, and resources AI clients consume. Harper implements MCP Streamable HTTP (spec rev 2025-06-18) with two independent profiles: `application` (your app's surface) and `operations` (Harper administration).

## When to Use

Reference these guidelines when:

- Enabling or configuring the MCP endpoint on a Harper instance
- Connecting an MCP client (Claude, agent frameworks, custom HTTP code) to Harper
- Deciding what tools an AI should see for a schema, or trimming that surface
- Exposing custom behavior (`mcpTools`), prompt templates (`mcpPrompts`), or content (`mcpResources`) to AI clients
- Protecting a public or anonymous-accessible MCP endpoint (rate limits, durable quotas, hardening)
- Debugging MCP wire errors (session/protocol headers, 400s, SSE)

## How It Works

1. Start with `enabling-mcp` to mount a profile, then `connecting-clients` for the handshake contract.
2. For the tool surface, consult `automatic-verb-tools` first — most CRUD needs are covered with zero code — and reach for `custom-mcp-tools` only for real behavior.
3. For content and templates, use `custom-mcp-resources` and `custom-mcp-prompts`; `resources-surface` explains what exists without any code.
4. Before any public exposure, work through `security-posture`'s checklist and configure `rate-limiting` (+ `durable-quotas` for cost-bearing tools).

## Examples

See the concrete examples embedded in each rule (curl handshakes, `static mcpTools`/`mcpResources` declarations, quota-hook implementations, and hardening configs).

<!-- BEGIN GENERATED INDEX -->

## Rule Categories by Priority

| Priority | Category | Impact | Prefix |
| -------- | --------------------- | ------ | ------------ |
| 1 | Setup & Connection | HIGH | `setup-` |
| 2 | Tools & Prompts | HIGH | `tools-` |
| 3 | Resources | MEDIUM | `resources-` |
| 4 | Operations & Security | HIGH | `ops-` |

## Quick Reference

### 1. Setup & Connection (HIGH)

- `enabling-mcp` — How to enable and configure Harper's MCP server profiles (application and operations).
- `connecting-clients` — How MCP clients connect to Harper - the initialize handshake, session and protocol-version headers, and authentication.

### 2. Tools & Prompts (HIGH)

- `automatic-verb-tools` — How Harper auto-generates CRUD MCP tools from exported tables, with RBAC filtering and allow/deny/maxTools controls.
- `custom-mcp-tools` — How to expose custom instance methods as MCP tools via static mcpTools, including the anonymous-exposure security model.
- `custom-mcp-prompts` — How to publish reusable prompt templates to MCP clients via static mcpPrompts.

### 3. Resources (MEDIUM)

- `resources-surface` — The MCP resources surface - harper:// metadata URIs, harper+rest:// table descriptors, templates, subscriptions, and list_changed notifications.
- `custom-mcp-resources` — How to serve custom content (docs pages, reports, binaries) as MCP resources via static mcpResources with URI templates and completions.

### 4. Operations & Security (HIGH)

- `rate-limiting` — MCP tools/call rate limiting - per-tool, per-session, and per-client-identity token buckets, and the identityHeader trust model.
- `durable-quotas` — Operator-pluggable durable quotas for MCP tools/call via the config-named quota Resource hook, with a race-safe counter pattern.
- `security-posture` — The MCP security model - anonymous access, RBAC boundaries, origin validation, audit logging, and the hardening checklist for public instances.

<!-- END GENERATED INDEX -->

## How to Use

Read individual rule files for detailed explanations and code examples:

```
rules/enabling-mcp.md
rules/connecting-clients.md
rules/custom-mcp-tools.md
rules/custom-mcp-resources.md
rules/security-posture.md
```

## Full Compiled Document

For the complete guide with all rules expanded: `AGENTS.md`
180 changes: 180 additions & 0 deletions harper-mcp/rules.manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# Rules manifest for the harper-mcp skill.
#
# Declarative source of truth for rule taxonomy, sources, and generation mode.
# All rules are currently synthesized (hand-authored from the Harper 5.1/5.2
# MCP implementation and its documentation). The commented `sources` /
# `must_cover` blocks below record the 1:1 mapping to canonical
# HarperFast/documentation pages for the rules that are candidates to flip to
# mode: generate (the schema only permits live sources/must_cover on generate
# rules; uncomment together with the mode flip once a generation run is
# reviewed). Rules without a mapping (connecting-clients' debugging guidance,
# custom-mcp-prompts — whose mcpPrompts feature is currently UNDOCUMENTED in
# reference/mcp/ — and the security-posture checklist) are agent-oriented
# synthesis with no single docs source and should stay synthesized.

rules:
# ===========================================================================
# Setup & Connection (priority 1 — HIGH)
# ===========================================================================

- rule: enabling-mcp
description: How to enable and configure Harper's MCP server profiles (application and operations).
category: setup
priority: 1
order: 1
mode: synthesized
# synthesized today; flip to generate once a generation run is reviewed
# sources:
# - path: reference/mcp/overview.md
# role: primary
# - path: reference/mcp/configuration.md
# role: supporting
# must_cover:
# - both profiles (application/operations) and their default ports
# - mountPath is what enables a profile
# - version availability of major MCP features
cross_links:
- connecting-clients
- rate-limiting

- rule: connecting-clients
description: How MCP clients connect to Harper - the initialize handshake, session and protocol-version headers, and authentication.
category: setup
priority: 1
order: 2
mode: synthesized

# ===========================================================================
# Tools & Prompts (priority 2 — HIGH)
# ===========================================================================

- rule: automatic-verb-tools
description: How Harper auto-generates CRUD MCP tools from exported tables, with RBAC filtering and allow/deny/maxTools controls.
category: tools
priority: 2
order: 1
mode: synthesized
# sources:
# - path: reference/mcp/tools-and-resources.md
# section: 'Application profile — tool generation'
# role: primary
# must_cover:
# - tool names preserve Resource-path case (get_Widget)
# - tools/list is RBAC-filtered per user; calls enforce permissions
# - exportTypes.mcp gating
cross_links:
- custom-mcp-tools

- rule: custom-mcp-tools
description: How to expose custom instance methods as MCP tools via static mcpTools, including the anonymous-exposure security model.
category: tools
priority: 2
order: 2
mode: synthesized
# sources:
# - path: reference/mcp/tools-and-resources.md
# section: 'Custom mcpTools opt-in'
# role: primary
# must_cover:
# - custom tools are exposed to every session including anonymous ones
# - live-class dispatch; gating is the method's responsibility
cross_links:
- rate-limiting
- durable-quotas

- rule: custom-mcp-prompts
description: How to publish reusable prompt templates to MCP clients via static mcpPrompts.
category: tools
priority: 2
order: 3
mode: synthesized
# No canonical docs source exists for mcpPrompts yet (shipped 5.1.10,
# undocumented in reference/mcp/) — stays synthesized until that docs
# gap is filled; content grounded in the implementation.

# ===========================================================================
# Resources (priority 3 — MEDIUM)
# ===========================================================================

- rule: resources-surface
description: The MCP resources surface - harper:// metadata URIs, harper+rest:// table descriptors, templates, subscriptions, and list_changed notifications.
category: resources
priority: 3
order: 1
mode: synthesized
# sources:
# - path: reference/mcp/tools-and-resources.md
# section: 'Resources surface'
# role: primary
# - path: reference/mcp/subscriptions.md
# role: supporting
# must_cover:
# - the harper:// metadata URIs and which profile serves each
# - harper+rest:// descriptor scheme with http(s) back-compat
# - subscribe requires an open GET SSE stream
cross_links:
- custom-mcp-resources

- rule: custom-mcp-resources
description: How to serve custom content (docs pages, reports, binaries) as MCP resources via static mcpResources with URI templates and completions.
category: resources
priority: 3
order: 2
mode: synthesized
# sources:
# - path: reference/mcp/tools-and-resources.md
# section: 'Custom mcpResources opt-in'
# role: primary
# must_cover:
# - exactly one of uri/uriTemplate per entry; {name} vs {+name} semantics
# - encoded-separator rejection preserves the single-segment contract
# - reserved schemes are rejected at registration
# - anonymous sessions are served; gating is the read method's job
cross_links:
- resources-surface
- rate-limiting

# ===========================================================================
# Operations & Security (priority 4 — HIGH for public deployments)
# ===========================================================================

- rule: rate-limiting
description: MCP tools/call rate limiting - per-tool, per-session, and per-client-identity token buckets, and the identityHeader trust model.
category: security
priority: 4
order: 1
mode: synthesized
# sources:
# - path: reference/mcp/configuration.md
# section: 'mcp.<profile>.rateLimit.*'
# role: primary
# must_cover:
# - session-scoped buckets are evadable by session cycling; per-client closes it
# - perClientBurst defaults to the rate, floored at one whole token
# - identityHeader is a spoofing trap unless the proxy strips it
cross_links:
- durable-quotas

- rule: durable-quotas
description: Operator-pluggable durable quotas for MCP tools/call via the config-named quota Resource hook, with a race-safe counter pattern.
category: security
priority: 4
order: 2
mode: synthesized
# sources:
# - path: reference/mcp/configuration.md
# section: 'mcp.<profile>.quota.*'
# role: primary
# must_cover:
# - fail-closed on hook errors or misconfiguration
# - hook runs after the in-memory buckets admit
# - read-modify-write counters must be atomic
cross_links:
- rate-limiting

- rule: security-posture
description: The MCP security model - anonymous access, RBAC boundaries, origin validation, audit logging, and the hardening checklist for public instances.
category: security
priority: 4
order: 3
mode: synthesized
50 changes: 50 additions & 0 deletions harper-mcp/rules/automatic-verb-tools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
name: automatic-verb-tools
description: How Harper auto-generates CRUD MCP tools from exported tables, with RBAC filtering and allow/deny/maxTools controls.
metadata:
mode: synthesized
---

# Automatic Verb Tools

The zero-code tool surface: every `@export`ed table becomes a family of CRUD tools on the application profile.

## When to Use

Use this skill when deciding what an MCP client will see for a given schema, when tools are unexpectedly missing from `tools/list`, or when trimming a large generated surface.

## How It Works

1. **Generation.** For each exported table `Widget`, the application profile registers `get_Widget`, `search_Widget`, `create_Widget`, `update_Widget`, and `delete_Widget` tools. Names preserve the Resource path's case (`/` and `.` become `_`, other non-identifier characters are dropped); path collisions get a deterministic database-name prefix. Input/output schemas are derived from the table's typed attributes, so clients get real parameter validation and result shapes.
2. **RBAC is enforced, twice.** `tools/list` is filtered per authenticated user (a user with no read permission on a table does not see its `get_`/`search_` tools), and calls run through the same permission enforcement as REST — including per-record `allow*` predicates on Resource subclasses. This is the key contrast with [custom tools](custom-mcp-tools.md), which are visible to everyone.
3. **`exportTypes` gating.** A Resource registered with `exportTypes: { mcp: false }` is excluded from MCP enumeration entirely, independent of its REST exposure.
4. **Surface controls.** On the application profile, trim per Resource with `exportTypes: { mcp: false }`; `maxTools` sets the `tools/list` page size (default 200, cursor pages overflow). The `allow`/`deny` glob filters belong to the **operations** profile's tool generation, not this one. Prefer trimming to what the AI actually needs — every tool costs client context.
5. **Live registration (5.1.18+).** The tool registry rebuilds lazily when the underlying Resource registry changes (schema changes, deploys, components that finish loading after boot), so tools stay in sync without restarts; connected sessions receive `notifications/tools/list_changed` when their visible set actually changes. On earlier 5.1.x, registration depends on schema-creation events — a restart on an existing data root can come up with an **empty custom-tool registry** (the tables already exist, so no event fires); upgrading is the fix.
6. **Plain `Resource` classes get partial tool families.** An exported non-table `Resource` subclass surfaces verb tools only for the REST verbs it actually has (typically a lone `create_*` from the base `post`). To host `mcpTools`/`mcpResources` without any verb surface, register the class via `server.resources.set(name, Class, { mcp: false })`-style exportTypes at registration — note a `static exportTypes` field on the class is NOT read.

## Examples

```graphql
# schema.graphql
type Widget @table @export {
id: ID @primaryKey
name: String @indexed
price: Float
}
```

With `mcp.application.mountPath` set, `tools/list` (as a user with read/write on Widget) includes:

```json
{ "name": "search_Widget", "inputSchema": { "properties": { "conditions": { "...": "..." } } } }
{ "name": "get_Widget", "inputSchema": { "properties": { "id": { "type": "string" } } } }
{ "name": "create_Widget", "...": "..." }
```

Excluding an exported Resource from MCP while keeping its REST surface:

```javascript
server.http(InternalThing, { name: 'internal-thing', exportTypes: { mcp: false } });
```

To expose read-only _data_, rely on RBAC: a role without write permissions never sees `create_`/`update_`/`delete_` tools for the table.
Loading