§00Developers
Integrations as code you didn’t have to write.
PartnerMCP writes every integration as a readable, versioned spec — with fixtures, diffs and environments. Review it like code, change it by asking, and add your own code where a rule needs it.
Full API reference is shared with early-access customers.
You
When a deal closes in Salesforce, create the customer and the sales order in Priority, and send delivery and invoice status back.
- Salesforce schema discoveredOpportunity · Account · OpportunityLineItem
- Priority API connectedREST (OData v4) · CUSTOMERS · ORDERS
integration: salesforce-prioritytrigger: on: salesforce.Opportunity # CDC when: IsWon = truesteps: - match: priority.CUSTOMERS by: stored CUSTNAME else: create - create: priority.ORDERS lines: ORDERITEMS_SUBFORM idempotency: Opportunity.Id - writeback: salesforce.Opportunity fields: [ORDNAME, ORDSTATUSDES]policies: rate_limit: 100/min per API user retry: [429, 5xx]tests: fixtures/*.yaml # 12 casesOne file says exactly what the integration does.
PartnerMCP writes it; your team reads it. Choose a part to see the lines behind it.
What starts a run: Salesforce Change Data Capture on
Opportunity, filtered onIsWon— stage names differ from org to org, the flag doesn't.What happens, in each system's own terms: match the customer on the stored Priority customer number, create the order with its lines, write the order number back.
Opportunity.is the idempotency key, so a replayed event can't create a second order.Id Every field mapping carries a confidence and the reason it was chosen —
Account.goes toName CUSTDES, becauseCUSTNAMEis the customer number. How mapping works.Limits and failure handling are written down, not remembered: Priority Cloud's 100 calls a minute per API user, retries for 429 and 5xx only, and validation errors held for a person.
Fixtures travel with the spec and run in the sandbox on every change. A version with a failing fixture isn't promoted.
What starts a run: Salesforce Change Data Capture on Opportunity, filtered on IsWon — stage names differ from org to org, the flag doesn't.
# written by PartnerMCP · reviewed by your teamintegration: salesforce-priorityversion: 1.4trigger: on: salesforce.Opportunity # Change Data Capture when: IsWon = true # not a stage labelsteps: - match: priority.CUSTOMERS by: Priority_Customer_No__c -> CUSTNAME else: create - create: priority.ORDERS lines: OpportunityLineItem -> ORDERITEMS_SUBFORM idempotency: Opportunity.Id # checked before every create - writeback: salesforce.Opportunity fields: [ORDNAME, ORDSTATUSDES, TOTPRICE]mappings: mappings/salesforce-priority.yamlpolicies: rate_limit: 100/min per API user # Priority Cloud fair use retry: [429, 5xx] # never validation errors on_validation_error: hold-for-reviewtests: fixtures/*.yaml # 12 cases, run on every changeChange it by asking. Review it like code.
A request becomes a diff with its impact and fixtures attached. It ships when the people your policy names approve it — and the previous version stays one step away.
YouRevOps
“Don't create ERP orders below $500 anymore.”
PartnerMCPproposed v1.5
I’ll add a minimum order value condition to the Salesforce → Priority production integration. Based on the last 30 days, this rule would have excluded 17 orders.
- Diff2 lines added, 0 removed
- Impact17 of 1,284 orders, last 30 days
- Fixtures14 of 14 passed · 2 new
- ApprovalIntegration owner
@@ -12,2 +12,4 @@ steps: else: create - condition: Opportunity.Amount >= 500 else: skip-and-log - create: priority.ORDERSSandbox
Testedv1.5
Salesforce sandbox · Priority test company
Production
Livev1.4
Salesforce production · Priority production
v1.5 is tested in the sandbox and waiting for the integration owner.
- Environments
- Each integration has a sandbox and production, each with its own connections and credentials — for Priority, a test environment or a duplicated company. A test can’t write to production.
- Promotion
- Only a tested version moves forward, and only with the approvals your policy names for that integration and that kind of change.
- Rollback
- Every production version stays deployable. Rolling back promotes the previous version: behaviour changes from that moment, records already written stay as they are.
Tests ship with the integration.
Fixtures cover the happy path and the ways real data goes wrong — duplicates, missing VAT numbers, unknown parts, rate limits, partial failures — and run on every change.
# fixtures/closed-won-new-customer.yamlgiven: salesforce.Opportunity: IsWon: true Amount: 12400.00 salesforce.Account: Name: Harbor Tools Ltd Priority_Customer_No__c: nullexpect: priority.CUSTOMERS: { created: 1, CUSTDES: Harbor Tools Ltd } priority.ORDERS: { created: 1, lines: 3 } salesforce.Account: { written_back: Priority_Customer_No__c } reconcile: ORDERS.DISPRICE == Opportunity.AmountA fixture states what the systems hold before a run and what must be true after it — in both systems’ own field names.
- closed-won-new-customercustomer and order created
- closed-won-existing-customermatched on CUSTNAME
- duplicate-change-eventno second order
- lines-without-pricepriced from the price list
- missing-vat-numberheld for review, as expected
- unknown-part-numberheld for review, as expected
- priority-returns-429retried after backoff
- partial-line-failureresumed from the failed line
- amount-differs-from-dispriceflagged, not overwritten
- hebrew-customer-nameCUSTDES preserved
- shipment-status-changedOpportunity updated
- order-number-writebackORDNAME on Opportunity
- below-minimum-amountnewskipped and logged
- at-minimum-amountneworder created
Code steps · in
Code where a rule needs code.
Most integrations need none. When one does — a checksum, a tenant-specific rule, a call to an internal service — add a code step. It is versioned with the spec, reviewed in the same diff and run against the same fixtures.
// steps/normalize-vat.ts · versioned and reviewed with the specexport default function normalizeVat(account: { taxId?: string }) { const digits = (account.taxId ?? "").replace(/\D/g, ""); if (digits.length === 0 || digits.length > 9) { return { hold: "VAT number missing or invalid" }; // a person decides } // Israeli company numbers are 9 digits: zero-pad shorter ones return { VATNUM: digits.padStart(9, "0") };} - code: steps/normalize-vat.ts input: Account.Tax_ID__c # custom field: Salesforce has no standard one tests: fixtures/vat/*.yamlEvents · out
Events when something happens.
PartnerMCP tells the rest of your stack what happened — to a webhook endpoint you own, or as a message to the people who need to act. Names and payloads here are illustrative; the reference is shared with early-access customers.
- run.completed
- A record made it through every step.
- run.failed
- A run stopped — with the step and the system's own error.
- record.held
- A record is waiting for a person, and why.
- change.proposed
- A new version is ready for review.
- version.promoted
- A version went live in an environment.
- schema.drift_detected
- A system's metadata no longer matches the spec.
POST https://hooks.example.com/partnermcp{ "id": "evt_8f2c41", "type": "record.held", "integration": "salesforce-priority", "version": "1.5", "environment": "production", "record": { "source": "salesforce.Opportunity", "target": "priority.ORDERS" }, "reason": "VATNUM is empty"}If it has an API, PartnerMCP can learn it.
Give it what you have — a spec, a collection, a schema, a database. It learns what the artifact says, and confirms in your sandbox what no artifact says.
openapi: 3.1.0info: { title: Fulfilment API, version: 2.3.0 }paths: /orders: post: operationId: createOrder /orders/{id}: get: operationId: getOrdercomponents: securitySchemes: oauth: { type: oauth2 }Learned
- Operations, paths and parameters
- Request and response schemas
- Security schemes and servers
Confirm in your sandbox
- Is createOrder safe to retry? Idempotency isn't declared.
- The real rate limit — the spec doesn't state one.
- How list endpoints paginate.
{ "info": { "name": "Fulfilment", "schema": "…/collection/v2.1.0/collection.json" }, "item": [{ "name": "Create order", "request": { "method": "POST", "url": "{{baseUrl}}/orders", "header": [{ "key": "Authorization", "value": "Bearer {{token}}" }] } }]}Learned
- Requests your team already knows work
- Auth setup and environment variables
- Real example bodies — often closer to the truth than the spec
Confirm in your sandbox
- Which saved examples still match current behaviour.
Collections often carry tokens. Secrets are stripped on import; credentials belong in the vault.
# introspection is off on this API: the SDL file is enoughtype Query { order(id: ID!): Order }type Mutation { createOrder(input: OrderInput!): Order }type Order { id: ID! status: OrderStatus! lines: [OrderLine!]! }enum OrderStatus { DRAFT RELEASED SHIPPED }Learned
- Types, queries and mutations
- Enums and required fields
Confirm in your sandbox
- Depth and cost limits.
- Which statuses are final.
Many teams disable introspection on internal APIs, as OWASP advises. Hand over the SDL file instead.
<wsdl:portType name="OrderService"> <wsdl:operation name="CreateOrder"> <wsdl:input message="tns:CreateOrderRequest"/> <wsdl:output message="tns:CreateOrderResponse"/> </wsdl:operation></wsdl:portType>Learned
- Operations, messages and bindings
- XSD types — enough for a typed client
Confirm in your sandbox
- WS-Security and session handling — usually defined outside the WSDL.
<EntityType Name="Order"> <Key><PropertyRef Name="OrderNo"/></Key> <Property Name="OrderNo" Type="Edm.String" MaxLength="16"/> <Property Name="Status" Type="Edm.String"/> <NavigationProperty Name="Lines" Type="Collection(Svc.OrderLine)"/></EntityType>Learned
- Entity types, keys and navigation properties
- Actions and functions
Confirm in your sandbox
- Business rules and posting logic — they aren't in the metadata.
-- discovery runs with a read-only roleSELECT table_name, column_name, data_typeFROM information_schema.columnsWHERE table_schema = 'sales';Learned
- Tables, columns, keys and foreign keys
- Whether change data capture is available
Confirm in your sandbox
- Meaning that lives in triggers and stored procedures.
Also: AsyncAPI 3 descriptions for event-driven APIs, SDKs and their docs, and flat files over SFTP — file layouts are learned from samples and confirmed with you, and idempotency comes from file names and checksums.
Connect a custom systemMCP, in both directions.
PartnerMCP uses MCP natively where a system offers it, and the system’s own API where that is safer. An MCP server for your agents is on the way — under the same rules as everyone else.
MCP client · today
Works through MCP where it’s the right path.
When a system ships an MCP server, PartnerMCP can use it — and goes to the system’s API where the server stops short. Vendor servers are real, and uneven:
- Priority ERPOfficial MCP server on Priority Cloud 26.0+. Request/response only, no form Actions — so order creation and change tracking stay on REST.
- Oracle NetSuiteAI Connector Service: records, reports and saved searches. Its SuiteQL tools are read-only.
- StripeRemote MCP server. Refunds and outbound payments need a person’s confirmation.
MCP server · planned
An MCP server for your own agents.
We’re designing a PartnerMCP MCP server, so the MCP-compatible clients your teams already use could ask what failed, read a run’s history or propose a change. It isn’t available yet. The rules it’s being designed around:
- A proposal from an agent goes through the same review as anyone else’s.
- An agent can’t approve its own change.
- Access is scoped to the integrations you allow, and every call is logged.
MCP is an open standard, hosted by the Agentic AI Foundation under the Linux Foundation. Its current revision is stateless and runs over Streamable HTTP.
Developer questions
Do I have to write the spec?
No. PartnerMCP writes it from your description and from what it discovers in both systems. Your team reads it, reviews changes to it and, where a rule needs code, adds a code step.
What runs in production — a model, or the spec?
The spec. PartnerMCP’s intelligence plans, maps, writes tests and diagnoses failures at design time. Production executes the approved, versioned spec step by step, the same way every time.
How does a change reach production?
As a new version: a diff, an impact estimate from recent runs, fixtures run in the sandbox, and an approval from the people your policy names. The previous version stays deployable for rollback.
Where is the API reference?
The full API reference is shared with early-access customers. The concept guides in the docs are public.
Does PartnerMCP have its own MCP server?
It’s planned, not available yet. Today PartnerMCP works as an MCP client: it uses vendors’ MCP servers where they are the right path, and their APIs where they aren’t.
§08Build
Bring a spec. Or a sentence.
Point PartnerMCP at an OpenAPI file, a Postman collection or a database — or describe what should happen. You’ll see the plan before anything is built.