MCP 伺服器安全,不代表背後的會計與 ERP 系統也安全
Your MCP Server Is Secure. The Ledger Behind It Isn’t.
作者以其團隊連接 32 個會計及 ERP 系統的經驗指出,MCP 伺服器的安全措施無法彌補上游系統在憑證撤銷、權限粒度及 Agent 身份記錄方面的不足。32 個系統中有 21 個使用 OAuth,約四成沒有可供整合方撤銷憑證的技術方式;作者也未找到能透過 API 同時記錄 Agent 及其代表之人的系統。
In a recent piece here on Unite.AI, Gil Feig laid out six best practices for building a secure MCP server. They are sound, and anyone shipping an MCP server should follow them. His advice to give each integration “its own fine-grained role, scoped strictly to required permissions” is exactly right. It also assumes the system on the other end has fine-grained roles. That points to a broader assumption that rarely gets stated: that the systems behind the server can be secured to the same standard.
In business software, they often cannot. I run the engineering team behind an integration layer that connects to 32 accounting and ERP systems, with an optional MCP server on top. We regularly see agents that are well authenticated, well scoped and well logged on our side, writing into systems that have no way of knowing an agent was involved at all.
This piece is about that second half of the problem: what the upstream systems actually offer, what you can control from the integration layer, and where that control ends.
Where the MCP Spec Hands Over
The MCP authorization specification is clear about its own boundary. The MCP server is an OAuth resource server for its clients. When it calls an upstream API, it acts as a separate OAuth client, with a separate token issued by the upstream system. Passing the client’s token through is explicitly forbidden.
That is the right design. It also means everything about the upstream call, including who is allowed to do what and how that is recorded, depends entirely on the upstream system. The spec cannot fix what the upstream system does not offer.
The same goes for the OWASP guidance on excessive agency. It recommends limiting the permissions an agent’s extensions hold in other systems to the minimum necessary and executing actions in the context of the user they act for. Both are good advice. Both assume the other system has a way to express minimum permissions and user context.
What the Upstream Systems Actually Offer
Here is what the 32 accounting and ERP systems we connect to look like from an integrator’s seat.
A third have no OAuth at all
21 of the 32 use OAuth. The other 11 rely on static credentials: API keys, username and password, or a pair of tokens. Some of those keys never expire. One widely used system documents its API tokens as having an unlimited lifetime for as long as the user exists.
Long life, little revocation
OAuth helps less than you would hope. One provider issues refresh tokens with a lifetime of roughly 20 years. That is a credential designed to outlive the agent using it, the framework the agent was built on, and quite possibly the person who clicked “allow”. In another system, even the access tokens do not expire.
And once a credential is out, the question is who can switch it off. The standard for that, OAuth token revocation (RFC 7009), has existed since 2013. Yet roughly four in ten of the systems give an integrator no technical way to revoke credentials. Every API-key system falls into that group. The only remaining control is asking the customer to delete the access by hand.
Coarse scopes, no agent identity
Most static keys simply inherit the full rights of the user who created them; only a few systems let you restrict a key to individual endpoints. Many OAuth systems have scopes, but they tend to be coarse, along the lines of “accounting, read and write”. And in none of the 32 systems could we find a way to record, through the API, both the agent and the person it acts for on the same transaction. External agents show up either as the user who connected them or as a generic system user. Tellingly, where a vendor has built agents into its own product, as Microsoft has in Business Central, it gave them dedicated user accounts. That is the same pattern I recommend below, just reserved for the vendor’s own agents.
What the Integration Layer Can Enforce
None of this means giving up. Between the agent and the accounting system, you control almost everything:
- per-agent credentials towards your own layer
- your own scopes, for example read-only access to invoices
- an audit log of every agent call, with the human it acted for
- idempotency keys, so a retrying agent does not book the same invoice twice
- rate limits per agent
- approval steps before any write
None of that depends on what the target system supports. A capable access layer at the integration tier is possible today, and if you put agents anywhere near financial data, you should build one.
Where It Stops
What you cannot do is extend that layer past the system boundary. Three things break there.
Attribution
Inside the accounting system, the agent’s write appears as whoever authorised the connection, or as a technical user. Anyone auditing that system sees a posting by that user. They cannot tell whether a person or an agent made it. To the ledger, an agent that books 400 invoices at 3 a.m. looks exactly like a very diligent finance manager. Reconstructing that requires the integrator’s logs, which is a different chain of trust from the system of record. For forensics or an audit, that is a weak position.
Most organisations are not ahead of this either. In a Cloud Security Alliance survey, only 28% of respondents said they could reliably trace agent actions to a human or system across all environments, and 44% use or plan to use static API keys for their agents.
Least privilege
You can enforce that an agent only reads invoices. But if the target system has no scopes, the credentials behind your layer still carry full access. Anyone who obtains them bypasses your layer entirely, and every rule you wrote with it.
Revocation
You can cut off your own agent instantly. That does not help if the credentials to the target system itself are compromised. And for the four in ten systems without a revocation endpoint, the kill switch is an email to the customer.
The Pragmatic Answer: A Dedicated Agent User
The most useful thing you can do today is unglamorous. Create a dedicated user for the agent in the target system and connect the agent through that user only.
It works on every system that lets you create users, and it buys three things the integration layer cannot:
- Attribution in the system of record. Postings show up as “AP agent”, not as the finance manager who clicked “connect” six months ago.
- A revocation path, even without an API for it. The customer can disable the user in the interface, which works on systems that offer no revocation endpoint.
- Partial least privilege. Where the system has any role model at all, the agent user can often be restricted to the modules it actually needs.
The costs are real. Someone has to create the user by hand during onboarding, which adds friction at exactly the wrong moment. About half of the systems charge for every additional user, from a few euros a month in small-business tools to more than a hundred in a full ERP. Several others cap users by plan, so one more user can mean a more expensive plan for the whole company. And a service user that nobody owns becomes its own risk, part of the non-human identity sprawl Unite.AI has covered before. It needs an owner and a review date like any other account.
It also does not fix scopes in systems that have none. But it moves attribution and revocation back into the system where auditors actually look.
The Structural Answer: Delegated Identity
The correct answer already exists on paper. OAuth 2.0 Token Exchange (RFC 8693) distinguishes impersonation from delegation. With delegation, the agent keeps its own identity and the token records that it acts on behalf of a person, through the “act” claim.
Applied to accounting, that would mean:
- the ledger records that this agent posted on behalf of this person
- scopes are granted per delegation, not per user
- a single delegation can be revoked without touching the person’s account
As far as I could find, none of the 32 systems supports anything like it. So for now it stays a direction, not an option. That makes it a request to the providers of accounting and ERP software rather than a task for integrators: agents are already writing to your ledgers, and your APIs should be able to say so.
What to Do Before an Agent Touches a Ledger
If you are connecting agents to accounting or ERP systems, a short checklist:
- Map each target system’s credential model. Is it OAuth or a static key, how long does the credential live, does it have scopes, and can you revoke it?
- Build your access layer anyway. Per-agent identity, scopes, idempotency and approvals belong on your side, whatever the target offers.
- Use a dedicated agent user wherever the system allows it. Accept the onboarding effort and license cost as the price of attribution.
- Keep your own audit trail tamper-evident. For many systems it will be the only record that an agent was involved.
- Write down the residual risk. Where a system has no scopes and no revocation, say so, to your customer and to your own risk register.
The Boundary Is the Point
Securing your MCP server is necessary. It is not sufficient. The security of an agent that writes to a ledger is decided at the boundary between your layer and the system of record, and today that boundary is set by the systems, not by you.
The good news is that the gap is well defined. The standards exist. What is missing is support for them in the systems that hold the books.
來源:Unite.AI · unite.ai