公司買了一台筆電給新同事,三年後這個同事離職。這時候 IT 要回答幾個問題:

  • 他手上有哪些公司的東西要收回來?
  • 他用的軟體授權,收回來之後可以給誰?
  • 這台筆電的保固還有多久,要不要汰換?

員工少的時候,一張試算表就夠了。人多了之後,試算表會跟現實對不起來:有人換了電腦沒登記、有人離職沒還、授權買了 50 套卻不知道有幾套還在用。

IT 資產管理系統要解的就是這件事:公司的每一樣東西,現在在誰手上。

核心的東西:資產、授權、借出紀錄

以 open source 的 Snipe-IT(AGPL-3.0)為例,它管的東西可以分成三類:

  • 資產:有序號、一個一個管的東西,例如筆電、螢幕、手機。每一台有自己的資產編號、購買日期、保固期。
  • 授權:軟體的使用席次。例如買了 5 套辦公軟體,就是 5 個席次,每個席次可以指派給一個人。
  • 借出與歸還:資產或席次交給某個人,叫借出(checkout);收回來,叫歸還(checkin)。每一次都會留下紀錄。

核心的流程只有一條:入庫 → 借出 → 歸還 → 再借出,直到報廢。 資產的狀態跟著流程走:待部署、已借出、封存。

這跟 ERP 那篇講的是同一個想法:每一個動作都留下紀錄,狀態從紀錄長出來,而不是另外記一本帳。

在本機跑起來

我用官方 image 加 docker compose,在本機跑了 Snipe-IT 8.8.0。三個容器(網站、資料庫、收信用的 Mailpit)合計大約 200 MB 記憶體。

架設時有兩件事值得記下來:

  • 官方範例的加密金鑰要自己產生。 官方的 .env.docker 裡寫死了一組 APP_KEY,照抄的話,每個照著範例架站的人金鑰都一樣。
  • 第一次啟動會導到網頁的設定精靈。 精靈做兩件事:建第一個管理員、建一筆系統設定。兩件都可以用指令完成,適合要自動化部署的情況。

接著灌了一批假資料:5 位員工、7 台筆電(購買日期和保固期各不相同)、1 套 5 個席次的軟體授權,部分借給員工。

為什麼要自己寫 MCP

2026-10 查證時,Snipe-IT 沒有官方的 MCP server,社群版本最多 32 顆星,而且沒有標示授權。它的 API 本身很完整,有 OpenAPI 文件。

這是一個典型的情況:系統有 API,但沒有好用的 MCP。 想讓 AI 查資產,就要自己包一層。

我寫了一個最小的 MCP server,不用任何套件,直接實作 MCP 的 JSON-RPC 協定,大約 130 行。它有三個工具:

工具回答的問題
find_assets哪些資產在誰手上、哪些可以借、哪些保固快到期
license_usage每套授權用了幾個席次、還剩幾個、在誰手上
prepare_offboarding某位員工離職時,要收回哪些東西

原則一:MCP 用唯讀帳號

MCP server 不用管理員的金鑰。我建了一個帳號,只給「檢視資產、檢視授權、檢視員工」的權限,再用它產生 API 金鑰。

實測結果:

  • 讀資產、讀員工:200
  • 借出資產:403
  • 刪除資產:403

就算 AI 被誘導去呼叫寫入的 API,這個帳號也做不到。權限在 Snipe-IT 這一層擋住,不是靠 MCP server 的程式碼自律。

過程中還踩到一個小坑:建帳號時如果設成「未啟用」,連讀取都會回 401。API 帳號也是帳號,要啟用才能用。

原則二:會改資料的事,只產生清單

離職是最適合 AI 幫忙的情境之一:把一個人名下的資產、授權全部列出來,比在畫面上一頁一頁點快得多。

但「歸還」是寫入的動作。所以 prepare_offboarding 只產生清單,並且明講下一步:

{
  "username": "zhihao",
  "assets": [
    { "tag": "IT-0004", "name": "lab-laptop-04", "holder": "zhihao", "warranty_expires": "2027-03-15" },
    { "tag": "IT-0005", "name": "lab-laptop-05", "holder": "zhihao", "warranty_expires": "2028-01-10" }
  ],
  "licenses": ["Office Suite"],
  "next_step": "A person with checkout rights must check these in. This tool does not write."
}

東西實際收回來了,才由有權限的人在系統裡按歸還。AI 列清單,人做確認,這跟 ERP 那篇「提交單據要人按」是同一條規則。

原則三:MCP 要把格式統一

這是寫 MCP 時最意外的發現。

第一版跑出來,授權的持有人清單是空的,離職清單裡的持有人是 null。查原始回應才發現,同一個概念「誰拿著它」,在三個 API 端點有三種格式:

  • 資產列表:持有人的資料裡有帳號名稱。
  • 授權席次:持有人有編號、姓名、email,沒有帳號名稱。
  • 某位員工名下的資產:持有人欄位是空的,因為「這個人」已經在網址裡了。

每一種單獨看都合理,合在一起就不一致。如果 MCP 直接把原始回應丟給 AI,AI 會看到三種格式,很容易答錯。

解法是在 MCP server 裡統一:先取一次員工清單,用員工編號對照出帳號名稱,所有工具都回同一種格式。這也是 MCP 存在的價值之一:它不只是把 API 包成工具,還要把系統的不一致擋在 AI 前面。

還有兩個細節:

  • Snipe-IT 的驗證錯誤回 HTTP 200。 例如名稱重複,HTTP 狀態碼是 200,錯誤寫在回應的 status 欄位。MCP server 只看狀態碼,就會把錯誤當成功。
  • 每個結果都附上查詢時間。 AI 回答時可以說「資料截至幾點幾分」,見怎麼觀察資料有沒有正常進來。

原則四:只回答問題需要的欄位

Snipe-IT 的員工資料有 email、電話、職稱、地址。回答「誰拿著這台筆電」只需要帳號名稱。

所以 MCP server 每個工具都只回固定的幾個欄位:資產編號、名稱、序號、型號、狀態、持有人、保固到期日。email 和電話不回。這跟 CRM 那篇講的「個資欄位要分級」是同一件事。

這次沒有驗證的事

我用一支測試腳本扮演 MCP host,逐一呼叫三個工具,確認回應正確。寫這篇時,我還沒有把它接到真的 AI 上測試,所以不知道 AI 會不會選對工具、看不看得懂參數。

後來的實測補上了這一段:四個問題,AI 都選對了工具和參數;要求它歸還筆電時,它明確回答「做不到,狀態沒有變」。

想看實作,可以讀這幾套

系統授權特色AI/MCP 現況(2026-10)
Snipe-ITAGPL-3.0專注資產和授權,API 完整沒有官方 MCP,社群版本最多 32 顆星且未標授權
GLPIGPL-3.0資產加上服務台工單,功能較廣沒有官方 MCP,社群版本最多 4 顆星

相關主題