@presentfast/mcp-server
v1.3.0
Published
Model Context Protocol server for PresentFast — lets Claude Desktop, Cursor, Codex, and Continue publish, list, rename, and read analytics for HTML/Markdown decks.
Maintainers
Readme
@presentfast/mcp-server
Model Context Protocol server for PresentFast. Lets Claude Desktop, Cursor, Codex, Continue, and any MCP-aware AI client publish HTML / Markdown decks, list your projects, fetch analytics, and rename presentations — all on your behalf.
Status: Phase 5 of the AI-first roadmap. Ships alongside @presentfast/cli.
What the AI can do
Once configured, your AI assistant gets ten tools:
| Tool | What it does |
|---|---|
| start_login | Begin (or finish) signing in via the device flow. Two-call UX: first call returns a URL + code to visit, second call completes after you authorize. |
| publish_presentation | Upload an .html or .md deck from a path on disk. Returns the public share URL. |
| list_presentations | List your presentations with id, title, creation date, and share URL. |
| get_presentation_analytics | Fetch total visits / unique visitors / clicks / avg time on page for one deck. |
| update_presentation | Rename a deck. |
| create_share_link | Create a gated share link with optional password, email capture, domain allowlist, expiry, or per-recipient tracking. |
| list_share_links | List all share links for a presentation and the gates on each. |
| update_share_link | Change gates on an existing link (pass null to clear a gate). |
| revoke_share_link | Turn off a share link so visitors can no longer open it (history kept). |
| get_share_link_leads | List email addresses captured by a link's email gate. |
Share links & gates
The five share-link tools let you create and manage gated share links for your presentations. All five require owner or editor access on the presentation and a valid login (start_login).
| Tool | Key args | What it does |
|---|---|---|
| create_share_link | project_id, password?, require_email?, allowed_domains?, expires_at?, label?, recipient_email?, recipient_name?, recipient_organization? | Creates a new link. allowed_domains (e.g. ["acme.com"]) implies require_email automatically. |
| list_share_links | project_id | Lists every link with its gates, view count, and full URL. Use this to find a link_id. |
| update_share_link | project_id, link_id, any gate fields | Updates only the fields you pass. Pass null to clear a gate (e.g. password: null removes the password). |
| revoke_share_link | project_id, link_id | Turns off the link; history is preserved. |
| get_share_link_leads | project_id, link_id | Returns emails captured by the link's email gate (name, date). |
Example — create a password-protected, email-gated link expiring 2026-07-01:
create_share_link({
project_id: "11111111-2222-3333-4444-555555555555",
password: "hunter2",
require_email: true,
expires_at: "2026-07-01T00:00:00Z",
label: "Q3 investor deck"
})The tool returns the full share URL. Use list_share_links to retrieve the link_id needed by the other tools.
The MCP server shares its credentials file with the CLI at ~/.config/presentfast/credentials.json (chmod 0600 on POSIX). If you've already run pf login from the CLI, the MCP server picks up that session automatically.
Team & collaboration
Seven tools let you manage team access on a presentation — listing and inviting members, changing roles, removing members, and acting on your own invitations. Invite/role/remove operations require owner access and a valid login (start_login).
| Tool | Key args | What it does |
|---|---|---|
| list_members | project_id | List all members (owner + collaborators) with their id, email, role, and status. Use to find a member_id for the other tools. |
| invite_member | project_id, email, role | Invite someone by email as editor, viewer, or analyst. Sends an invite email and returns the invite link. Requires owner access. |
| set_member_role | project_id, member_id, role | Change a collaborator's role to editor, viewer, or analyst. Requires owner access. |
| remove_member | project_id, member_id | Remove a collaborator (or let a member remove themselves to leave). Requires owner access. |
| list_invitations | (none) | List the current user's pending collaboration invitations with token, project, role, and who invited them. |
| accept_invitation | token | Accept a pending invitation by its token (from list_invitations). |
| decline_invitation | token | Decline a pending invitation by its token. |
Example — invite a colleague as an editor, then check the team roster:
invite_member({
project_id: "11111111-2222-3333-4444-555555555555",
email: "[email protected]",
role: "editor"
})
list_members({ project_id: "11111111-2222-3333-4444-555555555555" })Use the member_id from list_members with set_member_role or remove_member.
Install
npm install -g @presentfast/mcp-serverThis exposes a presentfast-mcp executable that speaks MCP over stdio.
Or run from source while developing:
git clone https://github.com/khush012/presentfast
cd presentfast/mcp-server
npm install && npm run build
# entry: ./dist/bin.jsConfigure your MCP client
The server is added to your AI client's MCP configuration. Examples below for the three most common clients in mid-2026.
Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows:
{
"mcpServers": {
"presentfast": {
"command": "presentfast-mcp",
"env": {
"PF_API_URL": "https://presentfast.com"
}
}
}
}Restart Claude Desktop. The PresentFast tools appear in the tool picker.
Dev override — point at a local server:
{
"mcpServers": {
"presentfast": {
"command": "node",
"args": ["/absolute/path/to/presentfast/mcp-server/dist/bin.js"],
"env": {
"PF_API_URL": "http://localhost:3000"
}
}
}
}Cursor
.cursor/mcp.json in your project root (or ~/.cursor/mcp.json for global):
{
"mcpServers": {
"presentfast": {
"command": "presentfast-mcp",
"env": {
"PF_API_URL": "https://presentfast.com"
}
}
}
}Reload Cursor. PresentFast appears under Settings → MCP.
Codex / Continue / generic MCP
Most clients accept the same shape:
{
"command": "presentfast-mcp",
"transport": "stdio",
"env": { "PF_API_URL": "https://presentfast.com" }
}See your client's MCP docs for the exact location and field names.
First-run flow
After the server is wired into your AI client:
- Prompt your AI: "Sign in to PresentFast."
- The AI calls
start_loginand returns a URL + 8-character code. - You visit the URL in any browser, authorize PresentFast for the MCP server, and click Allow.
- Tell the AI: "Continue."
- The AI calls
start_loginagain, which polls the server, gets your tokens, and reports "Logged in."
Now you can:
- "Publish
/Users/me/decks/q2-review.mdwith title 'Q2 review'." - "What's the analytics summary for project 11111111?"
- "Rename
11111111to 'Final Q2 review'." - "Show me all my decks."
Environment variables
| Var | Default | Description |
|---|---|---|
| PF_API_URL | http://localhost:3000 | PresentFast API origin. Set to https://presentfast.com for production. |
| PF_CLIENT_ID | presentfast-mcp-server | OAuth client id. Must match an allowlist entry. |
| PF_SCOPE | all | OAuth scope requested. |
| PF_ENV_FILE | unset | Optional path to a .env file loaded before reading any of the above. |
| XDG_CONFIG_HOME | ~/.config | Token-storage parent directory on POSIX. |
| APPDATA | %APPDATA% | Token-storage parent on Windows. |
The server loads .env files in this order (shell variables always win):
$PF_ENV_FILEif set./.env.localin the cwd~/.config/presentfast/.env(or$XDG_CONFIG_HOME/presentfast/.env)
Token storage
Credentials live in ~/.config/presentfast/credentials.json (%APPDATA%\presentfast\credentials.json on Windows) with mode 0600 on POSIX. The same file is read/written by the CLI, so logging in via one client signs you in for both.
Pending device-flow state lives at ~/.config/presentfast/mcp-pending-login.json between the two start_login calls. It's deleted automatically on success / denied / expired.
V1 limitations
- One file per
publish_presentationcall. Multi-section decks use---separators within a single.md. Multi-file.htmldecks are a CLI feature; the MCP server supports single-file uploads only in V1. - Asset bundling not supported. Relative
paths in markdown won't resolve because the asset is never uploaded. Use data URLs or absolute https URLs. - Synchronous polling in
start_login— the second call blocks for up to ~30 seconds waiting for approval. If your AI client's tool-call timeout is shorter, just callstart_loginagain to resume polling.
Troubleshooting
Tools missing from the AI client. Confirm the server starts: presentfast-mcp should hang on stdin (waiting for protocol messages). Logs go to stderr. Add 2>~/mcp.log to your launch command to capture them.
"Not logged in" error. Run start_login first, complete the device flow in your browser, then re-run the failing tool. Or use the CLI: pf login.
Token rotated but commands still 401. The MCP server caches credentials per process. Restart your AI client to pick up rotated tokens.
Connection refused on localhost. Make sure the Next.js dev server is running on PF_API_URL.
Architecture
The server is a thin TypeScript layer over the MCP SDK:
mcp-server/src/
├── bin.ts # stdio entry — wires deps, boots transport
├── server.ts # createServer(registry) — MCP SDK Server
├── tools/
│ ├── registry.ts # ToolDefinition shape + dispatch helpers
│ ├── index.ts # buildToolRegistry(deps)
│ ├── start-login.ts
│ ├── publish.ts
│ ├── list.ts
│ ├── analytics.ts
│ └── update.ts
└── lib/
├── api-client.ts # authedFetch with refresh-on-401 (duplicated from cli/)
├── credentials.ts # token storage (duplicated from cli/)
├── device-flow.ts # RFC 8628 polling (duplicated from cli/)
├── env-loader.ts # KEY=value parser (duplicated from cli/)
└── config.ts # PF_* env resolutionThe lib/* files marked "(duplicated from cli/)" share source-of-truth with @presentfast/cli for now; a future refactor will extract them into @presentfast/auth.
Development
npm install # install deps
npm test # run vitest unit tests
npm run build # compile to dist/
node dist/bin.js # run the server locally (it'll hang on stdin)Manual MCP smoke from a shell:
( echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"manual","version":"0"}}}'
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
) | node dist/bin.js | jqLicense
MIT — see LICENSE.
