Skip to content

poma-grill-mcp — Grill MCP Server

poma-grill-mcp is POMA AI's Model Context Protocol server for the Grill context engine. It exposes seven tools covering the full Grill loop: ingest (sync, async, batch, resume), search, job status, and a self-describing grill_explain. Two implementations ship in the same repo — a stable Go binary and a Node/TypeScript package — both speaking the same tool surface against the same backend. POMA also hosts the server, so you can use Grill from any MCP client without any local install.

  • Repo: github.com/poma-ai/poma-grill-mcp
  • Hosted endpoint: https://mcp.poma-ai.com/grill/v1
  • Implementations: Go (stable, default; Homebrew + go install + Docker), Node/TypeScript (npx, npm install -g, build-from-source)
  • Transports: stdio, streamable HTTP, Docker (Go only)
  • License: MPL-2.0

This server does not expose PrimeCut tools. For primecut_* tools (raw chunk JSON, .poma archive bytes), use poma-mcp. The two servers can run side-by-side in the same client config.

When to use this server

Pick poma-grill-mcp when:

  • You want prompt-ready RAG context from Grill without writing a single line of glue code in your agent.
  • You're ingesting large files and want the server to read them from disk via file_path instead of inflating tool calls with base64.
  • You want zero-install access via POMA's hosted endpoint at https://mcp.poma-ai.com/grill/v1.
  • You're building a backend service that uploads via HTTP — the Go binary has a dedicated POST /ingest-upload endpoint that accepts raw bytes or multipart with the same auth as MCP.

1. Get an API key

Sign up at console.poma-ai.com, create a project with product: "grill" (Create a project), and capture the project API key returned at creation. The key starts with poma_prod_gr_… — account-level POMA_API_KEY (prefix poma_acc_…) is rejected at the /grill/* boundary.

2. Install (skip for hosted)

If you're going to use the hosted endpoint, you don't need to install anything — jump to step 3, Option B.

Go binary

bash
brew tap poma-ai/poma-grill-mcp
brew install poma
which poma-grill-mcp
bash
go install github.com/poma-ai/poma-grill-mcp@latest
which poma-grill-mcp
bash
git clone https://github.com/poma-ai/poma-grill-mcp
cd poma-grill-mcp/go
go build -o bin/poma-grill-mcp .
realpath bin/poma-grill-mcp

Node / TypeScript

Requires Node 20+. Published as @poma-ai/poma-grill-mcp on npm.

bash
# Most MCP clients can invoke npx directly — no separate install needed
npx -y @poma-ai/poma-grill-mcp -input -
bash
npm install -g @poma-ai/poma-grill-mcp
poma-grill-mcp -input -
bash
git clone https://github.com/poma-ai/poma-grill-mcp
cd poma-grill-mcp/node
npm install
npm run build
node dist/index.js -input -

3. Add it to your agent

You have two options. Option B (hosted) is the easiest if your client supports type: "http" MCP servers.

Option A — local binary over stdio

Option A1: Go binary

json
{
  "mcpServers": {
    "poma-grill": {
      "command": "/full/path/to/poma-grill-mcp",
      "args": ["-input", "-"],
      "env": { "POMA_API_KEY": "your-api-key" }
    }
  }
}
json
{
  "mcpServers": {
    "poma-grill": {
      "command": "/full/path/to/poma-grill-mcp",
      "args": ["-input", "-"],
      "env": { "POMA_API_KEY": "your-api-key" }
    }
  }
}
json
{
  "mcpServers": {
    "poma-grill": {
      "command": "/full/path/to/poma-grill-mcp",
      "args": ["-input", "-"],
      "env": { "POMA_API_KEY": "your-api-key" }
    }
  }
}

Option A2: Node via npx (no install)

json
{
  "mcpServers": {
    "poma-grill": {
      "command": "npx",
      "args": ["-y", "@poma-ai/poma-grill-mcp", "-input", "-"],
      "env": { "POMA_API_KEY": "your-api-key" }
    }
  }
}

Option B — hosted HTTP endpoint (no install)

POMA hosts the server at https://mcp.poma-ai.com/grill/v1. Point your MCP client at it directly:

json
{
  "mcpServers": {
    "poma-grill": {
      "type": "http",
      "url": "https://mcp.poma-ai.com/grill/v1",
      "headers": { "x-api-key": "your-api-key" }
    }
  }
}
json
{
  "mcpServers": {
    "poma-grill": {
      "url": "https://mcp.poma-ai.com/grill/v1",
      "headers": { "x-api-key": "your-api-key" }
    }
  }
}

The hosted server runs on POMA's infrastructure, so it cannot read paths on your laptop. Use file_base64 when calling it from a hosted client, or use a local binary (Option A) when you need file_path.

After saving, restart the client. Sample prompt:

"Ingest ~/docs/contract.pdf into POMA Grill using file_path, then search it for 'termination clause'."

Tools

poma-grill-mcp exposes seven tools covering the full Grill loop. Both Go and Node implementations expose the same surface.

ToolWhat it does
grill_ingestStarts ingest; returns job_id after upload. Does not wait for indexing to finish.
grill_ingest_syncIngest + wait for terminal status. Returns job_id and the full events stream.
grill_ingest_resumeReconnect to an in-progress job's status stream and wait until terminal — without re-uploading.
grill_ingest_batchUpload up to 50 files with controlled concurrency. Returns job_ids as uploads complete.
grill_jobs_statusSnapshot the status of up to 50 jobs in one call. No streaming.
grill_searchHybrid search returning prompt-ready context. Use doc_filter to scope to one doc.
grill_explainReturns a markdown explanation of how Grill works. No arguments, no auth — useful for self-documenting agents.

doc_id vs job_id: when an ingest reaches done, the document's doc_id in Grill equals the job_id returned by ingest. Keep that value to feed doc_filter on subsequent searches.

grill_ingest and grill_ingest_sync

Both tools accept the same arguments. Provide exactly one of file_path or file_base64.

ArgumentTypeRequiredDescription
file_pathstringone-ofPath readable by the MCP server process (absolute or relative to its cwd). Best for large files; avoids giant JSON payloads.
file_base64stringone-ofStandard base64 of the file bytes. Fine for small files.
filenamestringnoOriginal basename (report.pdf). With file_path, defaults to the path basename; otherwise inferred from bytes.
tokenstringnoAPI key — overrides POMA_API_KEY for this call.

Notes on file_path

  • Works only when the server runs on the same machine as the file. The hosted MCP at mcp.poma-ai.com cannot read laptop paths — use file_base64 from there, or run the server locally.
  • GRILL_INGEST_ALLOWED_PREFIX (optional, env) — when set, file_path must resolve under that directory after symlinks are evaluated. Non-regular files are rejected. Use this in any environment where untrusted prompts can reach the server.
  • GRILL_INGEST_MAX_BYTES (env, default 512 MiB) — caps the payload size. Set to 0 to disable the limit (use with care).

Picking grill_ingest vs grill_ingest_sync

Use caseTool
Agent will search immediately and needs the doc indexed firstgrill_ingest_sync
Long ingest; agent will check back later; conversation context is preciousgrill_ingest, then poll with grill_jobs_status or reconnect with grill_ingest_resume

grill_ingest_resume

Reconnect to an already-running ingest job and wait for it to reach a terminal state. Use this when a previous grill_ingest returned a job_id (or the MCP connection dropped mid-ingest) and you don't want to re-upload the file.

ArgumentTypeRequiredDescription
job_idstringyesJob ID from a prior ingest.
tokenstringnoAPI key.

Returns the same job_id + events payload as grill_ingest_sync.

grill_ingest_batch

Upload up to 50 files in one tool call with controlled concurrency. Returns the job_ids as uploads complete — does not wait for indexing. Pair with grill_jobs_status to monitor.

ArgumentTypeRequiredDescription
file_pathsarray of stringyesUp to 50 paths readable by the MCP server process.
concurrencyintegernoUpload concurrency. Default 5, max 10. Use 1 on free-tier accounts.
tokenstringnoAPI key.

Returns { results, submitted_count, failed_count, quota_exceeded_count }. quota_exceeded entries (HTTP 403 from the queue) are retryable once running jobs finish.

grill_jobs_status

Get status snapshots for up to 50 jobs in a single call. Non-streaming — call on an interval if you want progress.

ArgumentTypeRequiredDescription
job_idsarray of stringyesUp to 50 job IDs to query.
tokenstringnoAPI key.

Returns { results, pending_count, done_count, failed_count }. Each result has { job_id, status, is_terminal, error? }.

Hybrid search across the project namespace. Result count is bounded server-side by relevance and a token budget — there is no top_k.

ArgumentTypeRequiredDescription
querystringyesNatural-language search query.
doc_filterstringnodoc_id (= job_id from ingest) to restrict search to one document.
exclude_doc_idsarray of stringnoDoc IDs to exclude from results (max 100). Useful in agent loops to avoid re-citing docs already shown.
return_assetsbooleannoInclude asset references (figures, tables) in the context.
return_page_imagesbooleannoInclude page-image references.
tokenstringnoAPI key.

Response (example):

json
{ "context": "<context>This is what is relevant […] inside your document.</context>" }

The context field is the entire payload — drop it straight into your LLM prompt. See RetrievalContext format for the wrapper grammar (<doc>, <gap />, sandwich ordering, citations).

grill_explain

Self-documentation tool. Takes no arguments and requires no authentication — returns a markdown explanation of how Grill works (ingest, search, result format, how to get an API key). Useful for agents that want to introspect their own capabilities, and for "explain this server" probes.

Output shapes

grill_ingest_sync waits for a terminal status and returns events:

json
{
  "job_id": "100c65a03a304aa343a1518aa79e8300-20260414T083549Z",
  "events": [
    { "status": "queued" },
    { "status": "chunking" },
    { "status": "chunked" },
    { "status": "grilled" },
    { "doc_id": "xxxxxx-xxxxx-xxxxx-xxxxx" }
  ]
}

grill_ingest (async variant) returns the same job_id immediately, without the trailing events.

On error, the MCP response sets isError: true and error describes the failure:

json
{ "error": "job failed: unsupported file type" }

HTTP mode

Both Go and Node binaries support a long-lived HTTP server for custom integrations:

bash
POMA_API_KEY=your-key poma-grill-mcp -http :8080            # Go
POMA_API_KEY=your-key node node/dist/index.js -http :8080   # Node
  • MCP endpoint: POST http://localhost:8080/v1 (standard streamable HTTP MCP).
  • Health check: GET http://localhost:8080/health.

Large uploads — POST /ingest-upload (Go binary only)

The Go binary exposes a dedicated upload endpoint that bypasses MCP framing for big files. Same auth as MCP — x-api-key, Authorization: Bearer, or fall back to POMA_API_KEY on the server.

  • Raw body: send file bytes as the body. Pass the basename via the ?filename=… query string or the X-Filename header.
  • Multipart: Content-Type: multipart/form-data with a part named file.
  • Response: 201 Created with {"job_id": "…"}. Size limits follow GRILL_INGEST_MAX_BYTES.
bash
curl -sS -X POST "http://localhost:8080/ingest-upload?filename=report.pdf" \
  -H "x-api-key: $POMA_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @./report.pdf

The returned job_id is the same one you'd pass to grill_search's doc_filter once indexing completes.

Docker (Go only)

bash
# HTTP mode
docker run -e POMA_API_KEY=your-key -p 8080:8080 \
  ghcr.io/poma-ai/poma-grill-mcp -http :8080

# Stdio (default entrypoint)
docker run -i -e POMA_API_KEY=your-key ghcr.io/poma-ai/poma-grill-mcp

A Node Docker image is not currently published — use npx or npm install -g instead.

Flags and environment

FlagDefaultDescription
-input <path|->Stdio mode: MCP on stdin (-) or a file path.
-http <addr>HTTP mode (e.g. :8080). Mutually exclusive with -input.

Both Go and Node accept the same flags.

Env varDefaultDescription
POMA_API_KEYGrill project API key (prefix poma_prod_gr_…) used when no token is passed at call time.
GRILL_INGEST_ALLOWED_PREFIXunsetRestrict file_path to a directory tree (post-symlink).
GRILL_INGEST_MAX_BYTES512 MiBMax upload payload. 0 disables the limit.

Tips for agent-driven workflows

  • For large files, instruct the agent to use file_path. Most clients default to file_base64. A short system-prompt cue like "When the user gives a local path, prefer file_path for grill_ingest_sync" saves enormous amounts of tokens.
  • Capture job_id after ingest. The agent can then issue follow-up grill_search calls scoped to that document with doc_filter — this is the difference between "search my whole namespace" and "chat with this PDF" UX.
  • Combine ingest + search in one turn. With grill_ingest_sync followed by grill_search, the agent can answer a question about a freshly uploaded file in a single response.
  • Bulk ingest folders with grill_ingest_batch + grill_jobs_status — submit everything once, poll status until terminal.

Troubleshooting

SymptomLikely causeFix
file_path: not foundHosted MCP is being asked to read a laptop pathUse file_base64, or run a local binary (Option A).
payload too largeFile exceeds GRILL_INGEST_MAX_BYTESRaise the env, use /ingest-upload (Go HTTP mode), or POST directly to the REST API.
forbidden / 401 on grill_*API key is account-level (poma_acc_…) or belongs to a primecut projectCreate a Grill project (projects) and use its project key (poma_prod_gr_…).
file_path rejected with "outside allowed prefix"GRILL_INGEST_ALLOWED_PREFIX is setMove the file under the prefix, or unset the env if you trust the caller.
Agent looks for primecut_* tools and finds nothingpoma-grill-mcp only ships grill_* toolsInstall poma-mcp alongside this server.

See also