Skip to main content
Glama
hulin42

keynote-harvest-mcp

by hulin42

Keynote Harvest MCP

This directory is the standalone keynote-harvest-mcp package, currently private and pending extraction to its own repository. It is intentionally separate from the existing mcp/keynote-case-study compatibility server while both remain in this branch.

It contains only the harvest-first MCP boundary:

  • Keynote app discovery.

  • Native .key to PDF export on macOS.

  • PDF-first harvest into previews, extractable text, assets, and a manifest.

  • Display-safe manifest reads.

  • Local harvest output listing.

  • MCP resources for manifests, previews, extracted embedded-image assets, and extracted text. Source PDFs stay readable by URI but are unlisted by default (KEYNOTE_HARVEST_LIST_SOURCE=1 lists them); a full deck as a base64 blob can exceed MCP host message limits.

It intentionally excludes CaseStudyComposition, proposals, portfolio preview routes, React/Next.js, and host preview hints. The existing server remains the compatibility and portfolio-example host while this package is hardened.

Requirements

  • macOS or Linux (declared via the package os field; Windows is unsupported).

  • Node.js 20 or newer.

  • Poppler commands pdfinfo, pdftoppm, and pdftotext for PDF harvests.

  • Poppler pdfimages for embedded-image asset extraction, which is on by default. Without pdfimages the harvest still completes and records a manifest warning; pass extractImages: false (CLI: --no-extract-images) to skip extraction, or extractImages: true (CLI: --extract-images) to require pdfimages and fail when it is missing.

  • macOS, Keynote, and Automation permission for native .key export only.

PDF harvesting can run without Keynote. OCR, vision, LLM calls, .key package parsing, and presenter-note extraction are intentionally absent.

Related MCP server: keynote-mcp

Manifest Contract

New harvests use schemaVersion: "keynote-harvest-manifest-v1". The package owns three aligned representations of that contract:

  • TypeScript types under src/types/.

  • Runtime structural validation under src/schema/.

  • A distributable Draft 2020-12 JSON Schema at schema/keynote-harvest-manifest-v1.schema.json.

The runtime validator requires the version by default. Its explicit allowLegacyVersion option exists only to inspect older private manifests created before schema versioning; newly generated manifests are always versioned.

Schema Evolution

Additive, optional fields may be introduced without changing keynote-harvest-manifest-v1. Any breaking contract change must mint keynote-harvest-manifest-v2 with a separate schema file, while the runtime validator retains support for reading v1. allowLegacyVersion remains limited to pre-versioned private manifests and is not a substitute for versioned schema migrations.

Install, Build, And Test

cd mcp/keynote-harvest
npm ci
npm run build
npm test

npm run test:clean-install copies the package to a temporary directory, runs npm ci, rebuilds it, and executes the package-owned tests without access to the portfolio repo's dependencies.

npm run test:packed-runtime builds a local tarball, installs it into an empty consumer project, starts the installed binary, and verifies the packaged tool surface. Neither rehearsal publishes anything.

npm run test:pdf-runtime generates a public-safe one-page PDF, harvests it through the compiled tool and local Poppler commands, validates the resulting v1 manifest, and removes all temporary output.

The built server and tools execute JavaScript from dist/; they do not execute source TypeScript at runtime.

Quickstart

Until the package is published, build it locally and point each stdio MCP host at the compiled entrypoint:

cd /absolute/path/to/keynote-harvest-mcp
npm ci
npm run build

Replace /absolute/path/to/node with the output of command -v node. GUI hosts should use that absolute executable path because they may not inherit your shell's PATH.

Claude Code

Local build:

claude mcp add keynote-harvest \
  -e KEYNOTE_HARVEST_WORKING_DIRECTORY=/path/to/your/working-directory \
  -e KEYNOTE_HARVEST_ROOT=.harvests \
  -- /absolute/path/to/node \
  /absolute/path/to/keynote-harvest-mcp/dist/index.js

After publish:

claude mcp add keynote-harvest \
  -e KEYNOTE_HARVEST_WORKING_DIRECTORY=/path/to/your/working-directory \
  -e KEYNOTE_HARVEST_ROOT=.harvests \
  -- npx -y keynote-harvest-mcp

Use --scope user when the server should be available outside the current project, and verify the registration with claude mcp get keynote-harvest.

Claude Desktop

For a local build, add this server to claude_desktop_config.json through Claude Desktop's developer settings, then restart the application:

{
  "mcpServers": {
    "keynote-harvest": {
      "command": "/absolute/path/to/node",
      "args": ["/absolute/path/to/keynote-harvest-mcp/dist/index.js"],
      "env": {
        "KEYNOTE_HARVEST_WORKING_DIRECTORY": "/path/to/your/working-directory",
        "KEYNOTE_HARVEST_ROOT": ".harvests"
      }
    }
  }
}

After publish, replace command and args with an absolute npx executable and the package invocation:

{
  "command": "/absolute/path/to/npx",
  "args": ["-y", "keynote-harvest-mcp"]
}

Keep the same env object in the published configuration.

Cursor

For a local build, create .cursor/mcp.json in a project, or ~/.cursor/mcp.json for a global configuration:

{
  "mcpServers": {
    "keynote-harvest": {
      "command": "/absolute/path/to/node",
      "args": ["/absolute/path/to/keynote-harvest-mcp/dist/index.js"],
      "env": {
        "KEYNOTE_HARVEST_WORKING_DIRECTORY": "/path/to/your/working-directory",
        "KEYNOTE_HARVEST_ROOT": ".harvests"
      }
    }
  }
}

After publish, replace command and args as shown in the Claude Desktop published configuration. Keep the same env object.

The package resolves relative input and output paths from the caller's current directory. Set KEYNOTE_HARVEST_WORKING_DIRECTORY when an MCP host should use a different working directory. KEYNOTE_HARVEST_ROOT, KEYNOTE_HARVEST_RESOURCE_SCHEME, and KEYNOTE_HARVEST_LIST_SOURCE are configurable.

GUI-launched MCP hosts often start servers with a minimal PATH. The package compensates: worker processes run under the server's own Node binary, and Poppler lookups also search /opt/homebrew/bin, /usr/local/bin, and /opt/local/bin. If Poppler lives elsewhere, set KEYNOTE_HARVEST_POPPLER_PATH to its directory. Long-running harvests are killed after 10 minutes by default; tune with KEYNOTE_HARVEST_COMMAND_TIMEOUT_MS.

Slide previews render at 144 DPI by default; pass previewDpi (36-600, CLI: --preview-dpi) to raise the resolution when previews double as reusable imagery. Harvests stop after 300 pages by default and record a truncation warning; pass maxPages (1-2000, CLI: --max-pages) to change the cap. Resource reads refuse files over 10 MB by default (KEYNOTE_HARVEST_MAX_RESOURCE_BYTES tunes the limit) so oversized blobs fail with a clear error instead of breaking the host.

Tool arguments are validated with zod against the same schemas advertised in tools/list; invalid calls fail fast with a field-by-field error message.

Security

Tool writes stay inside the configured harvest root unless a caller explicitly opts out. Agent-facing responses redact local paths by default, with clearly named debug modes for deliberate local inspection. Resource reads enforce lexical and symbolic-link containment, and source PDFs are unlisted by default.

Detailed controls:

  • Harvest slugs accept lowercase letters, numbers, and internal hyphens only.

  • Tool writes are contained: export_keynote_to_pdf outPath and harvest_keynote_pdf outDir must resolve inside the harvest root (lexically and through symbolic links). Pass allowOutsideHarvestRoot: true to write elsewhere deliberately. Source reads (keynotePath, pdfPath) are intentionally unrestricted.

  • Resource reads enforce both lexical containment and real-path containment, including symbolic links.

  • JSON resources remove known local-path fields before returning content.

  • get_harvest_manifest defaults to display-safe source metadata; local-debug and raw modes are explicit.

  • list_harvest_outputs defaults to relative/display-safe output metadata. Pass redactionMode: "local-debug" to include absolute local directories.

  • export_keynote_to_pdf defaults to display-safe source and application metadata. Pass redactionMode: "local-debug" for explicitly labeled local paths and command output.

Manifest and output paths used to continue a local pipeline remain classified as internal output paths. Resource URIs are the portable artifact identifiers exposed to MCP clients.

The package-scoped workflow at .github/workflows/keynote-harvest.yml runs Node 20, 22, and 24 package tests, clean-install and packed-runtime rehearsals, plus a real PDF harvest on Linux with Poppler.

This package remains private and unpublished.

Transport

The server runs on the official @modelcontextprotocol/sdk stdio transport (newline-delimited JSON-RPC, protocol version negotiation, and ping handled by the SDK). The smoke tests and the packed-runtime rehearsal connect with the official SDK client, so a spec-compliant MCP handshake is exercised on every test run. An earlier private iteration used hand-rolled Content-Length framing, which no mainstream MCP host speaks; that layer is gone.

A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Normalize and convert more than 400 file types via TweekIT's hosted MCP streamable HTTP endpoint.

  • List, share, upload, and manage Slideless HTML presentations from any MCP host.

  • Create App Store screenshots, icons, ASO copy, localization, and revisions via hosted MCP.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hulin42/keynote-harvest-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server