通过托管 OAuth 代理调用 Fireflies.ai GraphQL 接口访问会议数据。
文档
Granola
试用通过 MCP 用自然语言查询 Granola 会议记录、列出会议、获取详情和原始转录,鉴权由 Maton API Key 自动管理。
它能做什么
所有请求走 https://api.maton.ai/granola/{tool-name},由 Maton 代理到 mcp.granola.ai 并自动注入凭证,鉴权使用 MATON_API_KEY 环境变量配 Bearer Token,绑定账号需先调 POST /connections 再打开返回的 url 完成 OAuth。当前共四个 MCP 工具:query_granola_meetings 支持自然语言对话式查询;list_meetings 返回会议 ID、标题、日期与参会人;get_meetings 按 ID 拉取摘要、决议和行动项;get_meeting_transcript 给出带时间戳的原始转录(仅付费套餐)。响应统一包装为 MCP 的 {content:[{type:text,text:...}], isError:false} 格式;Maton 侧限流约每分钟 100 次,免费套餐只能查到近 30 天笔记。
什么时候用它
- 查本周分给我的会议行动项
- 列出最近的会议及参会人
- 按会议 ID 拉取摘要和决议
- 获取某次会议的原始转录
技能文档
Granola MCP
Access Granola via MCP (Model Context Protocol) with managed authentication.
Quick Start
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'query': 'What action items came from my last meeting?'}).encode()
req = urllib.request.Request('https://api.maton.ai/granola/query_granola_meetings', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://api.maton.ai/granola/{tool-name}
Maton proxies requests to mcp.granola.ai and automatically injects your credentials. The {tool-name} corresponds to the MCP tool name (e.g., query_granola_meetings).
Authentication
All requests require the Maton API key:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
Connection Management
Manage your Granola MCP connections at https://api.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=granola&method=MCP&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'granola', 'method': 'MCP'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "PENDING",
"creation_time": "2026-02-24T11:34:46.204677Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "granola",
"method": "MCP",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection
If you have multiple Granola connections, you must specify which MCP connection to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'query': 'What were my action items?'}).encode()
req = urllib.request.Request('https://api.maton.ai/granola/query_granola_meetings', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
Security & Permissions
- Access is scoped to meeting notes, transcripts, and documents within the connected Granola account.
- All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
MCP Reference
All MCP tools use POST method:
| Tool | Description | Schema |
|---|---|---|
query_granola_meetings | Chat with meeting notes using natural language | schema |
list_meetings | List meetings with metadata and attendees | schema |
get_meetings | Retrieve detailed content for specific meetings | schema |
get_meeting_transcript | Get raw transcript (paid tiers only) | schema |
Query Meetings
Chat with your meeting notes using natural language queries:
POST /granola/query_granola_meetings
Content-Type: application/json
{
"query": "What action items came from my meetings this week?"
}
Response:
{
"content": [
{
"type": "text",
"text": "You had 2 recent meetings:\n**Feb 4, 2026 at 7:30 PM** - \"Team sync\" [[0]](https://notes.granola.ai/d/abc123)\n- Action item: Review Q1 roadmap\n- Action item: Schedule follow-up with engineering\n**Jan 27, 2026 at 1:04 AM** - \"Finance integration\" [[1]](https://notes.granola.ai/d/def456)\n- Discussed workflow automation platforms\n- Action item: Evaluate n8n vs Zapier"
}
],
"isError": false
}
Use cases:
- "What action items were assigned to me?"
- "Summarize my meetings from last week"
- "What did we discuss about the product launch?"
- "Find all mentions of budget in my meetings"
List Meetings
List your meetings with metadata including IDs, titles, dates, and attendees:
POST /granola/list_meetings
Content-Type: application/json
{}
Response:
{
"content": [
{
"type": "text",
"text": "\n\n \n John Doe (note creator) from Acme \n Jane Smith from Acme \n \n \n\n\n \n John Doe (note creator) from Acme \n \n \n"
}
],
"isError": false
}
Response fields in XML format:
meetings_data: Container withfrom,todate range andcountmeeting: Individual meeting withid,title, anddateattributesknown_participants: List of attendees with name, role, company, and email
Get Meetings
Retrieve detailed content for specific meetings by ID:
POST /granola/get_meetings
Content-Type: application/json
{
"meeting_ids": ["0dba4400-50f1-4262-9ac7-89cd27b79371"]
}
Response:
{
"content": [
{
"type": "text",
"text": "\n\n \n John Doe (note creator) from Acme \n \n \n \n## Key Decisions\n- Approved Q1 roadmap\n- Budget increased by 15%\n\n## Action Items\n- @john: Review design specs by Friday\n- @jane: Schedule engineering sync\n\n\n"
}
],
"isError": false
}
Response includes:
- Meeting metadata (id, title, date, participants)
summary: AI-generated meeting summary with key decisions and action items- Enhanced notes and private notes (when available)
Get Meeting Transcript
Retrieve the raw transcript for a specific meeting (paid tiers only):
POST /granola/get_meeting_transcript
Content-Type: application/json
{
"meeting_id": "0dba4400-50f1-4262-9ac7-89cd27b79371"
}
Response (paid tier):
{
"content": [
{
"type": "text",
"text": "\n[00:00:15] John: Let's get started with the Q1 planning...\n[00:01:23] Jane: I've prepared the budget breakdown...\n[00:03:45] John: That looks good. What about the timeline?\n"
}
],
"isError": false
}
Response (free tier):
{
"content": [
{
"type": "text",
"text": "Transcripts are only available to paid Granola tiers"
}
],
"isError": true
}
Code Examples
JavaScript
const response = await fetch('https://api.maton.ai/granola/query_granola_meetings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
},
body: JSON.stringify({
query: 'What were the action items from my last meeting?'
})
});
const data = await response.json();
console.log(data.content[0].text);
Python
import os
import requests
# Query meeting notes
response = requests.post(
'https://api.maton.ai/granola/query_granola_meetings',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'query': 'What were the action items from my last meeting?'
}
)
print(response.json())
Error Handling
| Status | Meaning |
|---|---|
| 400 | Missing Granola connection |
| 401 | Invalid or missing Maton API key |
| 429 | Rate limited (approx 100 req/min) |
Troubleshooting: API Key Issues
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY
- Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Troubleshooting: Invalid App Name
- Ensure your URL path starts with
granola. For example:
- Correct:
https://api.maton.ai/granola/query_granola_meetings - Incorrect:
https://api.maton.ai/query_granola_meetings
Troubleshooting: MCP Parameter Errors
MCP tools return validation errors when required parameters are missing:
{
"content": [
{
"type": "text",
"text": "MCP error -32602: Input validation error: Invalid arguments for tool get_meetings: [\n {\n \"code\": \"invalid_type\",\n \"expected\": \"array\",\n \"received\": \"undefined\",\n \"path\": [\"meeting_ids\"],\n \"message\": \"Required\"\n }\n]"
}
],
"isError": true
}
Notes
- All IDs are UUIDs (with or without hyphens)
- MCP tool responses wrap content in
{"content": [{"type": "text", "text": "..."}], "isError": false}format - Users can only query their own meeting notes; shared notes from others are not accessible
- Basic (free) plan users are limited to notes from the last 30 days
- The
get_meeting_transcripttool is only available on paid Granola tiers
Resources
- Granola MCP Documentation
- Granola Help Center
- Maton Community
- Maton Support
常见问题
- 怎么完成鉴权和绑定 Granola 账号?
- 设置环境变量 MATON_API_KEY,在请求头里用 Authorization: Bearer $MATON_API_KEY。绑定账号需 POST /connections(app=granola, method=MCP),拿到返回的 url 在浏览器里完成 OAuth;同时连多个账号时,要额外带 Maton-Connection 头指明目标连接。
- 免费套餐能拿到完整转录吗?
- 不能。get_meeting_transcript 仅对付费 Granola 套餐开放;免费账号最多也只能查到最近 30 天的笔记。
- 遇到错误码怎么处理?
- 401 表示 MATON_API_KEY 无效或缺失,400 表示还没建过 Granola 连接,429 是限流(约每分钟 100 次)。路径前缀必须是 /granola/,否则会被当成错误的应用名。
相关技能
通过托管 OAuth 代理访问 Fathom API,获取会议录像、转写、摘要并管理 Webhook。
通过 OAuth 网关调度与管理 Zoom 会议、研讨会与云录制。
Granola (granola.ai). Use this skill for ANY Granola request — searching and reading data. Whenever a task involves Granola, use this skill instead of callin...
通过 Maton 网关和 MCP 协议接入 Notion,由平台代管 OAuth 凭据。
通过托管 OAuth 调用 Confluence Cloud API,管理页面、空间、博客、评论与附件。