关于 concur-mcp
concur-mcp 是连接 Claude 等 MCP 客户端与 SAP Concur 的非官方 MCP 服务,可管理报销单、费用、收据和行程。它使用已登录的浏览器会话,所有写入操作都需确认。
主要功能
- 01读取报销单、费用和行程
- 02创建和更新报销单及费用
- 03下载、上传和附加收据
- 04查看可用费用和收据
- 05写入前确认每项更改
适用场景
- 01查找未提交的报销单及阻止提交的问题
- 02将银行卡交易移入报销单
- 03上传并附加收据
- 04查看即将开始的行程
MCP 相关
向 MCP 客户端提供 SAP Concur 会话、报销单、费用、收据和旅行操作工具。写入操作需确认。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @chrischall/concur-mcpCONCUR_DCConcur datacenter from your signed-in tab's host (e.g. us2, eu2). Defaults to us2.CONCUR_WS_PORTfetchproxy bridge concentrator port. Defaults to the fleet-shared 37149.CONCUR_OUTPUT_DIRWhere `concur_get_receipt` saves downloaded receipts (never overwriting an existing file). Defaults to ~/Downloads/concur-mcp.CONCUR_UPLOAD_ROOTSThe only folders `concur_upload_receipt` will read from (a path-delimiter-separated list; `~` expanded). Hosted (with `MCP_DATA_DIR` set) the default is `$MCP_DATA_DIR/uploads`. Defaults to ~/Downloads, ~/Documents and ~/Desktop, plus the working directory when it is a folder inside your home directory (never `/` or home itself).CONCUR_INLINE_RECEIPTS`true` makes `concur_get_receipt` return the image in the result instead of writing a file. Off locally, on when hosted.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
39收录的工具列表 · 更新于 1 周前
此工具无需参数。
详细介绍
SAP Concur MCP
一个 Model Context Protocol 服务,可将 Claude 连接到 SAP Concur:你的费用报告、报告中的费用、可用(未分配)的费用、收据和 Concur Travel 行程——既可读取**,也**可写入,而且每次写入都必须经过确认。
警告
由 AI 开发的项目。 此代码库完全由 Claude 构建并主动维护。没有人审查过其实现。使用前请检查所有代码和工具权限。
注意
非官方且不受支持。 此服务不使用 Concur 的公开合作伙伴 API,而是调用 Concur Web 应用本身使用的内部 GraphQL API,并通过你已登录的浏览器会话进行身份验证。此服务可能会在没有通知的情况下失效,自动化使用也可能违反 SAP Concur 或你雇主的条款。请仅用于你自己的账户,并自行承担风险。
你可以做什么
可以向 Claude 提出这些问题:
- “我的 Concur 报告中,哪些尚未提交?是什么原因导致无法提交?”
- “显示还没有添加到报告中的银行卡交易。”
- “创建一份名为 ‘Austin offsite’ 的报告,并将上周的 Uber 和酒店费用移到该报告中。”
- “上传 ~/Downloads/dinner.pdf,并将其附加到晚餐费用。”
- “我的下一趟行程什么时候出发?我会住在哪家酒店?”
要求
- Claude Desktop、Claude Code 或任何 MCP 主机
- Node.js 22.5 或更高版本
- ContextMint Bridge 浏览器扩展,以及一个已登录 Concur 的标签页(
https://<dc>.concursolutions.com/…)
安装
Claude Code 插件
claude plugin marketplace add chrischall/concur-mcp
claude plugin install concur@chrischall
任何 MCP 主机(npx)
{
"mcpServers": {
"concur": {
"command": "npx",
"args": ["-y", "@chrischall/concur-mcp"],
"env": { "CONCUR_DC": "us2" }
}
}
}
Claude Desktop(.mcpb)
从最新版本安装 .mcpb 包。安装程序会询问你的数据中心(默认值为 us2)。
身份验证方式
Concur 的 Web 应用使用 HttpOnly JWT Cookie 对 API 调用进行身份验证,页面本身无法读取该 Cookie。本服务仅通过 fetchproxy 桥接程序,从你已登录的 Concur 标签页中读取三个会话 Cookie:JWT,以及 Concur 的旧版会话 Cookie OTSESSIONAABQRD 和 OTSESSIONAABQRN。之后,每次 API 调用都由 Node 发起,并携带 Authorization: Bearer <jwt> 和 Cookie 标头,其中包含该标签页持有的 OTSESSION Cookie——Concur 中仍由旧版服务提供的部分(报告密钥、货币、可用收据、权限)若缺少这些 Cookie,就会返回错误。Cookie 仅保存在内存中,不会出现在错误或日志里;你的主目录下唯一写入的内容是桥接程序的配对身份。
令牌有效期为 60 分钟。当令牌将在两分钟内过期时,服务器会从你的标签页重新读取 Cookie(一次性读取全部 Cookie);遇到 401 时也会重新读取一次(每次调用仅重新读取并重试一次,不会循环)。如果读取失败的原因与 OTSESSION Cookie 过期时相同,也会进行同样的一次重新读取和重试。Concur 会在标签页打开期间保持 Cookie 有效,因此使用这些工具时,请保持一个已登录的 Concur 标签页处于打开状态。concur_healthcheck 会报告令牌来源、剩余有效时间(分钟)以及是否找到旧版会话 Cookie,但绝不会显示任何 Cookie 值。
从早期版本升级? 桥接范围已从仅包含
JWT扩大为包含JWT和两个 OTSESSION Cookie。配对授权按范围区分,因此已配对的服务器必须重新批准一次:下次调用会返回新的配对码(或范围变更通知)——请在 ContextMint Bridge 弹出窗口中批准。
配对(仅需一次)
- 安装 ContextMint Bridge(Chrome:解压发布 zip 后以未打包方式加载),并在该浏览器中登录 Concur。
- 请 Claude 运行
concur_healthcheck。首次调用会返回一个配对码。 - 在 ContextMint Bridge 弹出窗口中批准该配对码。信任关系会在重启后继续保留(存储于
~/.fetchproxy/identity/)。
使用多个浏览器? 如果在多个浏览器中安装了 ContextMint Bridge,每个浏览器都会连接到同一个本地端口,并且可以在任意一个浏览器中批准配对码。请在持有 Concur 会话的浏览器中批准——服务器会锁定批准配对的扩展,只有该浏览器中的标签页才能提供 Cookie。stderr 中类似 refusing an extension whose identity is not the one this MCP paired with 的行,表示其他浏览器被拒绝;这不会造成影响。
配错了浏览器,或更换了浏览器? 在 ContextMint Bridge 弹出窗口中撤销 concur-mcp,使用 @fetchproxy/cli 中的 fpx trust clear concur-mcp 清除服务器锁定的扩展(或删除 ~/.fetchproxy/identity/concur-mcp.extension-trust.json),重启服务器,然后在正确的浏览器中重新配对。
配置
| 环境变量 | 默认值 | 用途 |
|---|---|---|
CONCUR_DC | us2 | 你的数据中心:已登录标签页主机名的第一个标签(us2 对应 us2.concursolutions.com,eu2 等)。必须与会话令牌的签发者匹配,否则每次调用都会失败,并提示应使用哪个值。 |
CONCUR_WS_PORT | 37149 | fetchproxy 桥接端口。整个 fetchproxy 集群和 ContextMint Bridge 共用 37149;仅在本地测试时(或主机为每个注册项注入独立端口时)覆盖此值。 |
CONCUR_OUTPUT_DIR | ~/Downloads/concur-mcp | concur_get_receipt 保存已下载收据的位置(绝不覆盖现有文件)。 |
CONCUR_UPLOAD_ROOTS | ~/Downloads、~/Documents、~/Desktop,以及当当前工作目录是你主目录下的文件夹时的该目录(绝不会是 / 或主目录本身 — Claude Desktop 会在 / 中启动服务) | concur_upload_receipt 唯一会读取的文件夹(以路径分隔符分隔的列表;会展开 ~)。托管环境中(设置了 MCP_DATA_DIR 时),默认值为 $MCP_DATA_DIR/uploads。 |
CONCUR_INLINE_RECEIPTS | 本地为 off,托管环境中为 on | true 会让 concur_get_receipt 在结果中返回图片,而不是写入文件。 |
MCP_USER_TZ | 服务所在时区 | 你的 IANA 时区(例如 America/New_York),当 concur_create_report 默认设置 reportDate 时用于确定“今天”。托管环境中请设置此值 — 托管服务运行在 UTC 时区,因此晚间创建的报告日期可能会变成明天。 |
CONCUR_DEBUG | off | 将桥接的角色和生命周期记录到 stderr。 |
MCP_CONFIRM_MODE | ask-user | 客户端无法显示确认提示时,写入操作的处理方式 — 见下文。 |
MCP_CONFIRM_ELICITATION | on | off 表示永不显示确认提示,因此所有客户端都会采用 MCP_CONFIRM_MODE 指定的处理路径(适用于声明支持提示但从不显示提示的客户端)。 |
确认写入操作
每个会更改 Concur 中内容(或发送邮件)的工具都需要经过确认:
- 支持 MCP elicitation 的客户端会显示真实的确认提示,准确说明将要发送的内容。
- **其他客户端(claude.ai、Claude Desktop)**的首次调用不会进行任何更改:它会返回将要发送内容的预览,以及一个一次性、短时有效的
confirmToken。只有再次调用并附带该令牌才会执行写入;如果期间请求中的任何内容发生变化,令牌将被拒绝。
MCP_CONFIRM_MODE 决定谁可以使用该令牌:
| 值 | 行为 |
|---|---|
ask-user(默认) | 模型必须向你展示预览,并在聊天中获得你的批准后才能再次使用该令牌。 |
auto | 模型查看预览后可以自行使用该令牌。 |
refuse | 在没有确认提示的客户端上拒绝写入操作。无法识别的值会按 refuse 处理。 |
从 Concur 返回的文本 — 供应商名称、评论、行程详情、邮件 — 都被视为不可信数据:它们绝不能授权写入操作。
工具
大多数读取工具都接受 view: compact | full | raw(默认值为 compact):compact 会省略你很少需要的字段,full 会保留所有字段,raw 则是未经投影处理的 Concur 响应。
会话与查询
| 工具 | 功能 |
|---|---|
concur_healthcheck | 令牌由哪个来源提供、API 是否接受该令牌、往返时间、距离过期还有多少分钟 |
concur_whoami | 你的 Concur 用户 ID、数据中心、令牌剩余有效分钟数,以及已启用的功能 |
concur_list_expense_types | 报告政策允许的费用类型(ID、名称、分组) |
concur_list_payment_types | 可用于费用的付款类型(现金、公司卡等) |
concur_list_currencies | Concur 接受的货币,可按条件筛选 |
concur_search_locations | 按城市查询费用地点(可选国家/行政区划) |
报告和费用(读取)
| 工具 | 功能 |
|---|---|
concur_list_reports | 按状态(ALL、ACTIVE、UNSUBMITTED、SENT_FOR_PAYMENT)和日期范围筛选你的报告 |
concur_get_report | 获取一份报告:抬头、所有费用条目及其例外情况(阻止提交的例外情况) |
concur_get_report_timeline | 获取报告的时间线(评论和工作流事件)及审计跟踪 |
concur_get_expense | 获取一笔费用:按标签显示的表单字段、明细项、收据、评论和例外情况 |
concur_list_available_expenses | 获取尚未添加到报告的卡交易、电子收据和移动端采集的费用 |
报告和费用(写入——所有操作均需确认)
| 工具 | 功能 | 可撤销? |
|---|---|---|
concur_create_report | 创建一份未提交的报告 | 是(concur_delete_report) |
concur_update_report | 更改抬头字段;仅发送有变更的内容 | 是 |
concur_delete_report | 删除一份未提交的报告及其上的所有费用 | 否 |
concur_add_report_comment | 添加审批人可见的评论 | 否(评论无法删除) |
concur_submit_report | 将报告发送给审批人 | 否——报告会送达他人;审批前可通过 concur_recall_report 撤回 |
concur_recall_report | 撤回已提交但尚未获批的报告 | 是 |
concur_create_expense | 向未提交的报告添加一笔费用;可按标签填写任何可编辑的表单字段(自定义字段、Ticket Number、From/To Location 等);外币将使用 Concur 针对该日期的汇率 | 是 |
concur_update_expense | 更改一笔费用,包括表单字段和汇率;仅发送有变更的内容 | 是 |
concur_delete_expenses | 从报告中删除费用(卡交易会返回可用费用列表) | 否 |
concur_copy_expense | 复制一笔费用 | 是 |
concur_move_available_expenses_to_report | 将可用费用移至报告 | 否(Concur 不支持移回) |
concur_delete_available_expenses | 删除可用费用 | 否 |
出席者
| 工具 | 功能 | 可撤销? |
|---|---|---|
concur_search_attendees | 按姓名或电子邮件搜索出席者目录(同事、已保存的访客) | 读取 |
concur_set_attendees | 替换一笔费用的出席者列表(默认先添加你自己),并平均分摊金额——需确认 | 否(没有工具可以读取之前的列表或清空列表) |
收据
| 工具 | 功能 | 需确认? |
|---|---|---|
concur_list_available_receipts | 列出收据存储区中尚未附加到费用的收据图片 | 读取 |
concur_get_receipt | 将收据图片下载到 CONCUR_OUTPUT_DIR(或以内联形式返回) | 仅本地文件 |
concur_upload_receipt | 从允许的文件夹上传 png / jpg / pdf(≤ 25 MB) | 是 |
concur_attach_receipt | 将已存储的图片附加到尚无收据的费用 | 是 |
concur_append_receipt | 将已存储的图片作为费用收据的额外页面添加 | 是 |
concur_detach_receipt | 从费用中移除图片 | 是 |
concur_add_missing_receipt_declaration | 为没有收据的费用添加 Missing Receipt Declaration(宣誓书)——你需要确认收据确实遗失;预览会显示你所在组织的声明文本。没有工具可以移除声明(附加收据会替换声明) | 是 |
concur_delete_receipt | 删除尚未附加的收据图片——无法撤销 | 是 |
差旅
| 工具 | 功能 |
|---|---|
concur_list_trips | 列出你的差旅(默认显示即将开始的行程;也可查看过去的行程或所有行程),支持筛选 |
concur_get_trip | 获取一趟行程及其航班、酒店、租车和铁路预订信息 |
concur_get_trip_history | 获取一趟行程的历史记录:变更、审批、行程单邮件 |
concur_send_itinerary | 通过电子邮件发送行程单——会发送真实邮件,需确认 |
应急接口
| 工具 | 功能 |
|---|---|
concur_list_operations | Concur 网页应用使用的 GraphQL 操作——名称、端点、用途,以及已有哪个专用工具会运行该操作 |
concur_graphql_query | 运行原始只读查询(spend 或 cds 端点);拒绝任何可能写入数据的操作 |
concur_graphql_mutation | 运行原始变更操作,需经完整文档预览确认;拒绝「范围外」中列出的操作,包括提交(请使用 concur_submit_report) |
范围外
Concur 中存在这些功能,但本项目有意不实现。不实现不等于拒绝:原始应急接口仍可访问以下任何未被防护机制明确限制的功能。
concur_graphql_mutation 会拒绝以下操作(按操作名称以及网页应用文本所选的字段匹配,因此改名或使用别名也无法绕过):processApproval、updateWorkItemStatus、startSearch、saveBookingSelections、holdTrip、confirmTrip、commitChange、tryCancelTripOrBooking 和 SubmitExpenseReport(请使用 concur_submit_report)。
- 审批——审批或退回他人的报告(
contextRole: MANAGER)。未实现:approvalsportal.asp页面、GetApproversList和loadApprovalDetails读取操作,以及UpdateTimelineWorkflow调用。拒绝:CDSprocessApproval和updateWorkItemStatus(updateDelegatesDashboardWorkItemStatus)。此服务仅处理你自己的数据。 - 卡片交易管理——卡片账户页面及其操作:
/Expense/Client/cardtransactions.asp、GetCardAccounts、GetCardTransaction、MoveCCTransactionsToReport、CreateCBSReportAndMoveCCTransactionsToReport、RefreshYodleeTransactions。(已显示为可用费用的卡片交易已覆盖——列出、移至报告、删除。) - 预订或取消旅行——搜索、查询价格、预订、暂存、确认或取消(
startSearch、saveBookingSelections、holdTrip、confirmTrip、commitChange、tryCancelTripOrBooking)。除发送行程邮件外,行程信息均为只读。
开发
npm install
npm run build # tsc → dist/, then esbuild → dist/bundle.js (the .mcpb entry)
npm test # typecheck + vitest
npm run test:coverage
本项目所基于的 API 接口——包括主机、身份验证、所用的每项操作以及已在线验证的内容——详见 docs/CONCUR-API.md,操作原文见 docs/api/。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。