salesforce-agent 2.3.2__tar.gz → 2.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {salesforce_agent-2.3.2/salesforce_agent.egg-info → salesforce_agent-2.3.4}/PKG-INFO +4 -8
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/README.md +0 -2
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/pyproject.toml +12 -17
- salesforce_agent-2.3.4/salesforce_agent/__init__.py +19 -0
- salesforce_agent-2.3.4/salesforce_agent/__main__.py +4 -0
- salesforce_agent-2.3.4/salesforce_agent/connector_sources.py +103 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/kg_ingest.py +3 -60
- salesforce_agent-2.3.4/salesforce_agent/mcp_server.py +49 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/certification.json +6 -9
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/mappings/source.yaml +1 -1
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/salesforce.ttl +3 -5
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/prompts/crm_specialist.json +0 -2
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4/salesforce_agent.egg-info}/PKG-INFO +4 -8
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/SOURCES.txt +1 -9
- salesforce_agent-2.3.4/salesforce_agent.egg-info/entry_points.txt +8 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/requires.txt +2 -5
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_fleet_name.py +3 -14
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_kg_ingest.py +8 -8
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_startup.py +2 -11
- salesforce_agent-2.3.2/MANIFEST.in +0 -4
- salesforce_agent-2.3.2/requirements.txt +0 -2
- salesforce_agent-2.3.2/salesforce_agent/__init__.py +0 -65
- salesforce_agent-2.3.2/salesforce_agent/__main__.py +0 -4
- salesforce_agent-2.3.2/salesforce_agent/connectors/__init__.py +0 -0
- salesforce_agent-2.3.2/salesforce_agent/connectors/mcp_source_presets.json +0 -29
- salesforce_agent-2.3.2/salesforce_agent/connectors/tool_schema_fingerprints.json +0 -8
- salesforce_agent-2.3.2/salesforce_agent/mcp_server.py +0 -99
- salesforce_agent-2.3.2/salesforce_agent/prompts/__init__.py +0 -0
- salesforce_agent-2.3.2/salesforce_agent/skills/__init__.py +0 -0
- salesforce_agent-2.3.2/salesforce_agent.egg-info/entry_points.txt +0 -17
- salesforce_agent-2.3.2/tests/test_default_content_surfaces.py +0 -43
- salesforce_agent-2.3.2/tests/test_init_dynamics.py +0 -12
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/LICENSE +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/__init__.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_admin.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_base.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_bulk.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_describe.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_query.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_records.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api_client.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/auth.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/mcp/__init__.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/mcp/mcp_salesforce.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/mcp_config.json +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/__init__.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/fixtures/records.json +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/migrations/manifest.json +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/shapes/connector.shacl.ttl +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/salesforce_input_models.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/salesforce_response_models.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-agent-operations/SKILL.md +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-agent-operations/agents/openai.yaml +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-agent-operations/references/catalog.md +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-crm-knowledge-graph/SKILL.md +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-crm-knowledge-graph/WORKFLOW.md +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-record-management/SKILL.md +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-record-management/WORKFLOW.md +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-soql-query/SKILL.md +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/skills/salesforce-soql-query/WORKFLOW.md +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/dependency_links.txt +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/top_level.txt +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/setup.cfg +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_admin.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_api_wrapper.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_auth.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_bulk.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_describe.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_errors.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_query.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_records.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_salesforce_mcp_validation.py +0 -0
- {salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/tests/test_salesforce_models.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: salesforce-agent
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: Salesforce REST/SOQL/Bulk API 2.0 connector + MCP Server + A2A Server for Agentic AI!
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Repository Maintainers <maintainers@knuckles.team>
|
|
6
6
|
License: MIT
|
|
7
7
|
Classifier: Development Status :: 4 - Beta
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -12,14 +12,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: <3.15,>=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: agent-connector-sdk[mcp]<
|
|
15
|
+
Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
|
|
16
16
|
Requires-Dist: httpx>=0.28.1
|
|
17
|
-
Provides-Extra: mcp
|
|
18
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "mcp"
|
|
19
17
|
Provides-Extra: jwt
|
|
20
18
|
Requires-Dist: cryptography>=50.0.2; extra == "jwt"
|
|
21
19
|
Provides-Extra: all
|
|
22
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.
|
|
20
|
+
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.4.1; extra == "all"
|
|
23
21
|
Requires-Dist: cryptography>=50.0.2; extra == "all"
|
|
24
22
|
Provides-Extra: test
|
|
25
23
|
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
|
|
@@ -40,8 +38,6 @@ Dynamic: license-file
|
|
|
40
38
|

|
|
41
39
|

|
|
42
40
|
|
|
43
|
-
*Version: 2.3.2*
|
|
44
|
-
|
|
45
41
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
46
42
|
> server live on the docs site:
|
|
47
43
|
> <https://knuckles-team.github.io/salesforce-agent/>
|
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|

|
|
10
10
|

|
|
11
11
|
|
|
12
|
-
*Version: 2.3.2*
|
|
13
|
-
|
|
14
12
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
15
13
|
> server live on the docs site:
|
|
16
14
|
> <https://knuckles-team.github.io/salesforce-agent/>
|
|
@@ -4,43 +4,33 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "salesforce-agent"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.4"
|
|
8
8
|
description = "Salesforce REST/SOQL/Bulk API 2.0 connector + MCP Server + A2A Server for Agentic AI!"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
classifiers = [ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", "Environment :: Console", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3",]
|
|
11
11
|
requires-python = ">=3.12, <3.15"
|
|
12
|
-
dependencies = [ "agent-connector-sdk[mcp]>=0.
|
|
12
|
+
dependencies = [ "agent-connector-sdk[mcp]>=0.5.4,<0.6.0", "httpx>=0.28.1",]
|
|
13
13
|
[[project.authors]]
|
|
14
|
-
name = "
|
|
15
|
-
email = "maintainers@
|
|
14
|
+
name = "Repository Maintainers"
|
|
15
|
+
email = "maintainers@knuckles.team"
|
|
16
16
|
|
|
17
17
|
[project.license]
|
|
18
18
|
text = "MIT"
|
|
19
19
|
|
|
20
20
|
[project.optional-dependencies]
|
|
21
|
-
mcp = [ "agent-connector-sdk[mcp]>=0.3.18,<1.0.0",]
|
|
22
21
|
jwt = [ "cryptography>=50.0.2",]
|
|
23
|
-
all = [ "agent-connector-sdk[mcp]>=0.
|
|
22
|
+
all = [ "agent-connector-sdk[mcp]>=0.4.1,<1.0.0", "cryptography>=50.0.2",]
|
|
24
23
|
test = [ "pytest-xdist>=3.8.0", "pytest>=9.1.1", "pytest-asyncio>=1.4.0", "pytest-cov>=7.1.0", "cryptography>=50.0.2",]
|
|
25
24
|
|
|
26
25
|
[project.scripts]
|
|
27
|
-
salesforce-mcp = "
|
|
28
|
-
|
|
29
|
-
[project.entry-points."agent_connector_sdk.skill_providers"]
|
|
30
|
-
salesforce-agent = "salesforce_agent.skills"
|
|
31
|
-
|
|
32
|
-
[project.entry-points."agent_connector_sdk.ontology_providers"]
|
|
33
|
-
salesforce-agent = "salesforce_agent.ontology"
|
|
34
|
-
|
|
35
|
-
[project.entry-points."agent_connector_sdk.source_connector_providers"]
|
|
36
|
-
salesforce-agent = "salesforce_agent.connectors"
|
|
26
|
+
salesforce-mcp = "agent_connector_sdk.cli:serve"
|
|
37
27
|
|
|
38
28
|
[project.entry-points."agent_connector_sdk.prompt_providers"]
|
|
39
29
|
salesforce-agent = "salesforce_agent.prompts"
|
|
40
30
|
|
|
41
31
|
# The one declared connector identity: the fleet name (SDK-CONNECTOR-CONTROL-R071).
|
|
42
32
|
[project.entry-points."agent_connector_sdk.connector"]
|
|
43
|
-
salesforce-mcp = "salesforce_agent"
|
|
33
|
+
salesforce-mcp = "salesforce_agent:connector"
|
|
44
34
|
|
|
45
35
|
[tool.uv.workspace]
|
|
46
36
|
members = ["."]
|
|
@@ -54,6 +44,7 @@ override-dependencies = [
|
|
|
54
44
|
]
|
|
55
45
|
|
|
56
46
|
[tool.ruff]
|
|
47
|
+
extend-exclude = ["tests", "scripts"]
|
|
57
48
|
line-length = 88
|
|
58
49
|
target-version = "py312"
|
|
59
50
|
|
|
@@ -81,3 +72,7 @@ ignore_names = ["request", "config", "exc_info"]
|
|
|
81
72
|
|
|
82
73
|
[tool.pipelines_hooks.ste]
|
|
83
74
|
exempt = ["specs/*", "specs/**/*"]
|
|
75
|
+
|
|
76
|
+
[tool.pipelines.container]
|
|
77
|
+
debug_apt = ["default-jre", "ripgrep", "tree", "fd-find", "curl", "nano", "build-essential", "cmake", "libssl-dev", "libcurl4-openssl-dev", "pkg-config", "cargo", "rustc"]
|
|
78
|
+
limits = {"mcp" = {"memory_limit_env" = "AGENT_CONTAINER_MEMORY_LIMIT", "memory_limit" = "4g", "cpu_limit_env" = "AGENT_CONTAINER_CPU_LIMIT", "cpu_limit" = "2.0"}}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""CONCEPT:AU-ECO.messaging.native-backend-abstraction Unified ecosystem initialization dynamic check."""
|
|
2
|
+
|
|
3
|
+
from agent_connector_sdk.connector import Connector
|
|
4
|
+
|
|
5
|
+
from salesforce_agent.api_client import Api
|
|
6
|
+
from salesforce_agent.auth import SalesforceAuth, SalesforceConfig, get_client
|
|
7
|
+
from salesforce_agent.mcp_server import _operation_targets
|
|
8
|
+
|
|
9
|
+
__all__ = ["Api", "SalesforceAuth", "SalesforceConfig", "connector", "get_client"]
|
|
10
|
+
|
|
11
|
+
connector = Connector(
|
|
12
|
+
tools="salesforce_agent.mcp_server",
|
|
13
|
+
instructions="Salesforce MCP Server — SOQL/SOSL queries, record CRUD with composite/collections batching, metadata describe, Bulk API 2.0 ingest, and org administration. Destructive operations are gated by SALESFORCE_ALLOW_DESTRUCTIVE.",
|
|
14
|
+
transports=(
|
|
15
|
+
"stdio",
|
|
16
|
+
"streamable-http",
|
|
17
|
+
),
|
|
18
|
+
verbose_targets=tuple(_operation_targets()),
|
|
19
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Data sources of this connector, declared by tool name (generated by connector-ontology-map migrate).
|
|
2
|
+
|
|
3
|
+
Served live as ``connector://resources``. Regenerate by editing the declarations, not the tools.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# ruff: noqa: E501
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from agent_connector_sdk.ingest.live_declaration import source_meta
|
|
10
|
+
|
|
11
|
+
SOURCES = (
|
|
12
|
+
source_meta(
|
|
13
|
+
tool="salesforce_soql_query",
|
|
14
|
+
source_id="salesforce-opportunities",
|
|
15
|
+
record_type="salesforce_opportunity",
|
|
16
|
+
id_field="Id",
|
|
17
|
+
preset={
|
|
18
|
+
"doc_type": "salesforce_opportunity",
|
|
19
|
+
"params": {
|
|
20
|
+
"soql": "SELECT Id, Name, StageName, Amount, CloseDate, Description FROM Opportunity",
|
|
21
|
+
},
|
|
22
|
+
"params_style": "args",
|
|
23
|
+
},
|
|
24
|
+
records_path="records",
|
|
25
|
+
server="salesforce-mcp",
|
|
26
|
+
text_field="Description",
|
|
27
|
+
title_field="Name",
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
SCHEMA_VERSION = 2
|
|
32
|
+
|
|
33
|
+
FIELD_SETS = {
|
|
34
|
+
"fields_1": {
|
|
35
|
+
"amount": "xsd:decimal",
|
|
36
|
+
"closeDate": "xsd:date",
|
|
37
|
+
"email": "xsd:string",
|
|
38
|
+
"industry": "xsd:string",
|
|
39
|
+
"leadStatus": "xsd:string",
|
|
40
|
+
"salesforceId": "xsd:string",
|
|
41
|
+
"stageName": "xsd:string",
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
SCHEMA_MAPPINGS = {
|
|
46
|
+
"Account": {
|
|
47
|
+
"field_sets": ["fields_1"],
|
|
48
|
+
"ontology_class": None,
|
|
49
|
+
},
|
|
50
|
+
"Campaign": {
|
|
51
|
+
"field_sets": ["fields_1"],
|
|
52
|
+
"ontology_class": None,
|
|
53
|
+
},
|
|
54
|
+
"Case": {
|
|
55
|
+
"field_sets": ["fields_1"],
|
|
56
|
+
"ontology_class": None,
|
|
57
|
+
},
|
|
58
|
+
"Contact": {
|
|
59
|
+
"field_sets": ["fields_1"],
|
|
60
|
+
"ontology_class": "Person",
|
|
61
|
+
},
|
|
62
|
+
"Lead": {
|
|
63
|
+
"field_sets": ["fields_1"],
|
|
64
|
+
"ontology_class": None,
|
|
65
|
+
},
|
|
66
|
+
"Opportunity": {
|
|
67
|
+
"field_sets": ["fields_1"],
|
|
68
|
+
"ontology_class": None,
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
RESOURCES = (
|
|
73
|
+
{
|
|
74
|
+
"id_prefix": "account",
|
|
75
|
+
"label": "Account",
|
|
76
|
+
"name": "Account",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"id_prefix": "campaign",
|
|
80
|
+
"label": "Campaign",
|
|
81
|
+
"name": "Campaign",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id_prefix": "case",
|
|
85
|
+
"label": "Case",
|
|
86
|
+
"name": "Case",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id_prefix": "contact",
|
|
90
|
+
"label": "Contact",
|
|
91
|
+
"name": "Contact",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"id_prefix": "lead",
|
|
95
|
+
"label": "Lead",
|
|
96
|
+
"name": "Lead",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id_prefix": "opportunity",
|
|
100
|
+
"label": "Opportunity",
|
|
101
|
+
"name": "Opportunity",
|
|
102
|
+
},
|
|
103
|
+
)
|
|
@@ -14,71 +14,14 @@ import logging
|
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
16
16
|
from agent_connector_sdk.ingest import (
|
|
17
|
-
ChangeSet,
|
|
18
|
-
Entity,
|
|
19
|
-
IngestBinding,
|
|
20
17
|
IngestError,
|
|
21
18
|
KnowledgeIngest,
|
|
22
|
-
|
|
23
|
-
current_ingest,
|
|
19
|
+
SourceStream,
|
|
24
20
|
)
|
|
25
21
|
|
|
26
22
|
logger = logging.getLogger("salesforce_agent.kg")
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
_ENTITY_RESERVED_KEYS = frozenset({"id", "node_type"})
|
|
31
|
-
_RELATIONSHIP_RESERVED_KEYS = frozenset({"source", "target", "relationship"})
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _to_entity(record: dict[str, Any]) -> Entity:
|
|
35
|
-
return Entity(
|
|
36
|
-
id=record.get("id"),
|
|
37
|
-
node_type=record.get("node_type"),
|
|
38
|
-
properties={
|
|
39
|
-
key: value
|
|
40
|
-
for key, value in record.items()
|
|
41
|
-
if key not in _ENTITY_RESERVED_KEYS
|
|
42
|
-
},
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _to_relationship(record: dict[str, Any]) -> Relationship:
|
|
47
|
-
properties = {
|
|
48
|
-
key: value
|
|
49
|
-
for key, value in record.items()
|
|
50
|
-
if key not in _RELATIONSHIP_RESERVED_KEYS
|
|
51
|
-
}
|
|
52
|
-
return Relationship(
|
|
53
|
-
source=record["source"],
|
|
54
|
-
target=record["target"],
|
|
55
|
-
relationship=record["relationship"],
|
|
56
|
-
properties=properties or None,
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
async def ingest_entities(
|
|
61
|
-
entities: list[dict[str, Any]],
|
|
62
|
-
relationships: list[dict[str, Any]] | None = None,
|
|
63
|
-
*,
|
|
64
|
-
ingest: KnowledgeIngest | None = None,
|
|
65
|
-
) -> dict[str, int]:
|
|
66
|
-
"""Write canonical typed nodes and relationships via the SDK ingest facade.
|
|
67
|
-
|
|
68
|
-
Uses canonical ``node_type`` / ``relationship`` structural fields and surfaces
|
|
69
|
-
a malformed change set or a refused commit as ``IngestError``.
|
|
70
|
-
"""
|
|
71
|
-
if not entities:
|
|
72
|
-
raise IngestError("ingest_entities needs at least one entity")
|
|
73
|
-
change_set = ChangeSet(
|
|
74
|
-
entities=tuple(_to_entity(entity) for entity in entities),
|
|
75
|
-
relationships=tuple(
|
|
76
|
-
_to_relationship(relationship) for relationship in relationships or ()
|
|
77
|
-
),
|
|
78
|
-
)
|
|
79
|
-
service = ingest or current_ingest()
|
|
80
|
-
receipt = await service.submit(_BINDING, change_set)
|
|
81
|
-
return {"nodes": receipt.affected_count, "edges": receipt.relationship_count}
|
|
24
|
+
STREAM = SourceStream.for_package(__package__.split(".")[0], "salesforce")
|
|
82
25
|
|
|
83
26
|
|
|
84
27
|
# --------------------------------------------------------------------------- #
|
|
@@ -283,4 +226,4 @@ async def ingest_records(
|
|
|
283
226
|
if mapper is None:
|
|
284
227
|
raise IngestError(f"unsupported Salesforce object: {sobject!r}")
|
|
285
228
|
entities, relationships = mapper(records)
|
|
286
|
-
return await
|
|
229
|
+
return await STREAM.entities(entities, relationships, ingest=ingest)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Main FastMCP server and tool registration for the Salesforce connector."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from salesforce_agent.api import (
|
|
6
|
+
AdminClient,
|
|
7
|
+
BulkClient,
|
|
8
|
+
DescribeClient,
|
|
9
|
+
QueryClient,
|
|
10
|
+
RecordsClient,
|
|
11
|
+
)
|
|
12
|
+
from salesforce_agent.auth import get_client
|
|
13
|
+
from salesforce_agent.mcp.mcp_salesforce import (
|
|
14
|
+
register_admin_tools,
|
|
15
|
+
register_bulk_tools,
|
|
16
|
+
register_describe_tools,
|
|
17
|
+
register_ingest_tools,
|
|
18
|
+
register_records_tools,
|
|
19
|
+
register_soql_tools,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# SDK discovery registers the register_<tag>_tools functions bound in this module.
|
|
23
|
+
__all__ = [
|
|
24
|
+
"register_admin_tools",
|
|
25
|
+
"register_bulk_tools",
|
|
26
|
+
"register_describe_tools",
|
|
27
|
+
"register_ingest_tools",
|
|
28
|
+
"register_records_tools",
|
|
29
|
+
"register_soql_tools",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _operation_targets() -> list[dict[str, Any]]:
|
|
34
|
+
"""One operation-tool group per resource client of the ``Api`` facade."""
|
|
35
|
+
resources = {
|
|
36
|
+
"soql": QueryClient,
|
|
37
|
+
"records": RecordsClient,
|
|
38
|
+
"describe": DescribeClient,
|
|
39
|
+
"bulk": BulkClient,
|
|
40
|
+
"admin": AdminClient,
|
|
41
|
+
}
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
"client_cls": client_cls,
|
|
45
|
+
"get_client": (lambda name=name: getattr(get_client(), name)),
|
|
46
|
+
"prefix": f"salesforce_{name}",
|
|
47
|
+
}
|
|
48
|
+
for name, client_cls in resources.items()
|
|
49
|
+
]
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/certification.json
RENAMED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"api_version": "
|
|
2
|
+
"api_version": "graphos.io/v1",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"connector_manifest.yml": "8f242e7c62b075786c8c47967e40d62aa44a967593782ae679771dc27e4693e8",
|
|
5
|
-
"salesforce_agent/connectors/mcp_source_presets.json": "644ed7237882e5b5ac96b1c16696e1348a15f025c0d10c23745dfcd8ea6d0c87",
|
|
6
|
-
"salesforce_agent/connectors/tool_schema_fingerprints.json": "f2db55d366dd1f4b9da00ac78433cbc0a627109d15a23d3a5bdda3d493e1c8f3",
|
|
7
4
|
"salesforce_agent/ontology/fixtures/records.json": "b344913dc0bbc8999151a56c1802f1c15cf818888a0ab8aaa5063326b21e9043",
|
|
8
|
-
"salesforce_agent/ontology/mappings/source.yaml": "
|
|
5
|
+
"salesforce_agent/ontology/mappings/source.yaml": "5292026d92f27af428a32e62d8ece64aa25ee3ef81212f11d960bfb0da614af1",
|
|
9
6
|
"salesforce_agent/ontology/migrations/manifest.json": "76e71d3e6fbb573e65cb9ce25868523b5aa8ba1f4cca15b266d343ee9d2b42fc",
|
|
10
|
-
"salesforce_agent/ontology/salesforce.ttl": "
|
|
7
|
+
"salesforce_agent/ontology/salesforce.ttl": "fd5b77e12fd1db5ba65d45bba24657e70aa8e60682b51a234d93f2b762ef45c1",
|
|
11
8
|
"salesforce_agent/ontology/shapes/connector.shacl.ttl": "643358fd71781e6efc38edfac45ad28cf895741e5d29836e9542d33eda7193f4"
|
|
12
9
|
},
|
|
13
10
|
"checks": {
|
|
@@ -18,11 +15,11 @@
|
|
|
18
15
|
"synthetic_fixture_contract": "passed"
|
|
19
16
|
},
|
|
20
17
|
"compatibility": {
|
|
21
|
-
"
|
|
18
|
+
"agent_utilities": ">=2.5.0,<3",
|
|
22
19
|
"bundle_schema": "2",
|
|
23
20
|
"epistemic_graph": ">=2.27.0,<3"
|
|
24
21
|
},
|
|
25
|
-
"connector": "salesforce-
|
|
22
|
+
"connector": "salesforce-agent",
|
|
26
23
|
"kind": "ConnectorSourceAttestation",
|
|
27
24
|
"live_certified": false,
|
|
28
25
|
"mode": "offline-source",
|
|
@@ -32,5 +29,5 @@
|
|
|
32
29
|
"signer": "UNSIGNED-PREVIEW",
|
|
33
30
|
"signing_public_key": "",
|
|
34
31
|
"status": "source-validated",
|
|
35
|
-
"validated_at": "2026-
|
|
32
|
+
"validated_at": "2026-10-24T12:23:32Z"
|
|
36
33
|
}
|
|
@@ -13,9 +13,8 @@
|
|
|
13
13
|
# (salesforce_soql / salesforce_records / salesforce_describe / salesforce_ingest_crm).
|
|
14
14
|
# :Person (shared) is REUSED for the owning Salesforce User — never redefined here.
|
|
15
15
|
|
|
16
|
-
:Account a owl:Class
|
|
17
|
-
|
|
18
|
-
rdfs:comment "A company or organization tracked in Salesforce CRM (sObject Account)." .
|
|
16
|
+
:Account a owl:Class .
|
|
17
|
+
|
|
19
18
|
|
|
20
19
|
:Contact a owl:Class ;
|
|
21
20
|
rdfs:label "Contact" ;
|
|
@@ -131,5 +130,4 @@
|
|
|
131
130
|
rdfs:comment """Salesforce CRM model — accounts, contacts, opportunities, leads,
|
|
132
131
|
cases and campaigns with their sales and service relationships — federated into
|
|
133
132
|
the agent-connector-sdk knowledge-graph hub. Reuses the shared :Person for the owning
|
|
134
|
-
Salesforce User."""
|
|
135
|
-
owl:imports <http://knuckles.team/kg/enterprise> .
|
|
133
|
+
Salesforce User.""" .
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/prompts/crm_specialist.json
RENAMED
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
"schema_version": "1.0",
|
|
5
5
|
"prompt_version": "0.1.0",
|
|
6
6
|
"source": "salesforce-agent",
|
|
7
|
-
"extends": "agent-connector-sdk:base",
|
|
8
|
-
"compose": "append",
|
|
9
7
|
"description": "Salesforce CRM specialist: SOQL/SOSL analysis, safe record management, and knowledge-graph ingestion over the salesforce-agent MCP server.",
|
|
10
8
|
"metadata": {
|
|
11
9
|
"topic": "Salesforce CRM",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: salesforce-agent
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: Salesforce REST/SOQL/Bulk API 2.0 connector + MCP Server + A2A Server for Agentic AI!
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Repository Maintainers <maintainers@knuckles.team>
|
|
6
6
|
License: MIT
|
|
7
7
|
Classifier: Development Status :: 4 - Beta
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -12,14 +12,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: <3.15,>=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: agent-connector-sdk[mcp]<
|
|
15
|
+
Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
|
|
16
16
|
Requires-Dist: httpx>=0.28.1
|
|
17
|
-
Provides-Extra: mcp
|
|
18
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "mcp"
|
|
19
17
|
Provides-Extra: jwt
|
|
20
18
|
Requires-Dist: cryptography>=50.0.2; extra == "jwt"
|
|
21
19
|
Provides-Extra: all
|
|
22
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.
|
|
20
|
+
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.4.1; extra == "all"
|
|
23
21
|
Requires-Dist: cryptography>=50.0.2; extra == "all"
|
|
24
22
|
Provides-Extra: test
|
|
25
23
|
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
|
|
@@ -40,8 +38,6 @@ Dynamic: license-file
|
|
|
40
38
|

|
|
41
39
|

|
|
42
40
|
|
|
43
|
-
*Version: 2.3.2*
|
|
44
|
-
|
|
45
41
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
46
42
|
> server live on the docs site:
|
|
47
43
|
> <https://knuckles-team.github.io/salesforce-agent/>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
LICENSE
|
|
2
|
-
MANIFEST.in
|
|
3
2
|
README.md
|
|
4
3
|
pyproject.toml
|
|
5
|
-
requirements.txt
|
|
6
4
|
salesforce_agent/__init__.py
|
|
7
5
|
salesforce_agent/__main__.py
|
|
8
6
|
salesforce_agent/api_client.py
|
|
9
7
|
salesforce_agent/auth.py
|
|
8
|
+
salesforce_agent/connector_sources.py
|
|
10
9
|
salesforce_agent/kg_ingest.py
|
|
11
10
|
salesforce_agent/mcp_config.json
|
|
12
11
|
salesforce_agent/mcp_server.py
|
|
@@ -25,9 +24,6 @@ salesforce_agent/api/api_client_bulk.py
|
|
|
25
24
|
salesforce_agent/api/api_client_describe.py
|
|
26
25
|
salesforce_agent/api/api_client_query.py
|
|
27
26
|
salesforce_agent/api/api_client_records.py
|
|
28
|
-
salesforce_agent/connectors/__init__.py
|
|
29
|
-
salesforce_agent/connectors/mcp_source_presets.json
|
|
30
|
-
salesforce_agent/connectors/tool_schema_fingerprints.json
|
|
31
27
|
salesforce_agent/mcp/__init__.py
|
|
32
28
|
salesforce_agent/mcp/mcp_salesforce.py
|
|
33
29
|
salesforce_agent/ontology/__init__.py
|
|
@@ -37,9 +33,7 @@ salesforce_agent/ontology/fixtures/records.json
|
|
|
37
33
|
salesforce_agent/ontology/mappings/source.yaml
|
|
38
34
|
salesforce_agent/ontology/migrations/manifest.json
|
|
39
35
|
salesforce_agent/ontology/shapes/connector.shacl.ttl
|
|
40
|
-
salesforce_agent/prompts/__init__.py
|
|
41
36
|
salesforce_agent/prompts/crm_specialist.json
|
|
42
|
-
salesforce_agent/skills/__init__.py
|
|
43
37
|
salesforce_agent/skills/salesforce-agent-operations/SKILL.md
|
|
44
38
|
salesforce_agent/skills/salesforce-agent-operations/agents/openai.yaml
|
|
45
39
|
salesforce_agent/skills/salesforce-agent-operations/references/catalog.md
|
|
@@ -53,11 +47,9 @@ tests/test_admin.py
|
|
|
53
47
|
tests/test_api_wrapper.py
|
|
54
48
|
tests/test_auth.py
|
|
55
49
|
tests/test_bulk.py
|
|
56
|
-
tests/test_default_content_surfaces.py
|
|
57
50
|
tests/test_describe.py
|
|
58
51
|
tests/test_errors.py
|
|
59
52
|
tests/test_fleet_name.py
|
|
60
|
-
tests/test_init_dynamics.py
|
|
61
53
|
tests/test_kg_ingest.py
|
|
62
54
|
tests/test_query.py
|
|
63
55
|
tests/test_records.py
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
agent-connector-sdk[mcp]<
|
|
1
|
+
agent-connector-sdk[mcp]<0.6.0,>=0.5.4
|
|
2
2
|
httpx>=0.28.1
|
|
3
3
|
|
|
4
4
|
[all]
|
|
5
|
-
agent-connector-sdk[mcp]<1.0.0,>=0.
|
|
5
|
+
agent-connector-sdk[mcp]<1.0.0,>=0.4.1
|
|
6
6
|
cryptography>=50.0.2
|
|
7
7
|
|
|
8
8
|
[jwt]
|
|
9
9
|
cryptography>=50.0.2
|
|
10
10
|
|
|
11
|
-
[mcp]
|
|
12
|
-
agent-connector-sdk[mcp]<1.0.0,>=0.3.18
|
|
13
|
-
|
|
14
11
|
[test]
|
|
15
12
|
pytest-xdist>=3.8.0
|
|
16
13
|
pytest>=9.1.1
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from agent_connector_sdk.connector_identity import connector_name
|
|
5
6
|
import ast
|
|
6
|
-
import json
|
|
7
|
-
import re
|
|
8
7
|
import tomllib
|
|
9
8
|
from pathlib import Path
|
|
10
9
|
|
|
@@ -36,18 +35,8 @@ def _call_connectors(path: Path) -> list[str]:
|
|
|
36
35
|
def test_connector_name_is_the_fleet_name() -> None:
|
|
37
36
|
pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))
|
|
38
37
|
assert pyproject["project"]["entry-points"]["agent_connector_sdk.connector"] == {
|
|
39
|
-
FLEET: "salesforce_agent"
|
|
38
|
+
FLEET: "salesforce_agent:connector"
|
|
40
39
|
}
|
|
41
|
-
|
|
42
|
-
if not manifest_path.is_file():
|
|
43
|
-
manifest_path = ROOT / "connector_manifest.yml"
|
|
44
|
-
manifest = manifest_path.read_text(encoding="utf-8")
|
|
45
|
-
match = re.search(r'^\s*"?connector"?\s*:\s*"?([^"\s,]+)', manifest, re.MULTILINE)
|
|
46
|
-
assert match is not None and match.group(1) == FLEET
|
|
47
|
-
fingerprints = PACKAGE / "connectors" / "tool_schema_fingerprints.json"
|
|
48
|
-
if fingerprints.is_file():
|
|
49
|
-
assert (
|
|
50
|
-
json.loads(fingerprints.read_text(encoding="utf-8"))["connector"] == FLEET
|
|
51
|
-
)
|
|
40
|
+
assert connector_name("salesforce_agent") == FLEET
|
|
52
41
|
for module in sorted(PACKAGE.glob("*.py")):
|
|
53
42
|
assert all(name == FLEET for name in _call_connectors(module)), module.name
|
|
@@ -19,7 +19,7 @@ from epistemic_graph.generated.source_ingestion import SourceIngestionRequest
|
|
|
19
19
|
|
|
20
20
|
from salesforce_agent.kg_ingest import (
|
|
21
21
|
INGEST_QUERIES,
|
|
22
|
-
|
|
22
|
+
STREAM,
|
|
23
23
|
ingest_records,
|
|
24
24
|
map_leads,
|
|
25
25
|
)
|
|
@@ -54,7 +54,7 @@ def ingest() -> tuple[KnowledgeIngest, _FakeTransport]:
|
|
|
54
54
|
@pytest.mark.asyncio
|
|
55
55
|
async def test_ingest_entities_writes_nodes_and_edges(ingest):
|
|
56
56
|
service, transport = ingest
|
|
57
|
-
res = await
|
|
57
|
+
res = await STREAM.entities(
|
|
58
58
|
[
|
|
59
59
|
{"id": "a", "node_type": "Account", "name": "Acme"},
|
|
60
60
|
{"id": "b", "node_type": "Contact"},
|
|
@@ -70,7 +70,7 @@ async def test_ingest_entities_writes_nodes_and_edges(ingest):
|
|
|
70
70
|
a_record = next(r for r in request.records if r.record_id == "a")
|
|
71
71
|
assert a_record.payload["name"] == "Acme"
|
|
72
72
|
assert request.relationships[0].relation_reference.endswith(
|
|
73
|
-
"
|
|
73
|
+
"relations/Contact/worksAtAccount"
|
|
74
74
|
)
|
|
75
75
|
|
|
76
76
|
|
|
@@ -94,7 +94,7 @@ async def test_ingest_records_accounts_with_owner(ingest):
|
|
|
94
94
|
r.record_id == "salesforce:User:005U" for r in request.records
|
|
95
95
|
)
|
|
96
96
|
assert request.relationships[0].relation_reference.endswith(
|
|
97
|
-
"
|
|
97
|
+
"relations/Account/ownedBy"
|
|
98
98
|
)
|
|
99
99
|
|
|
100
100
|
|
|
@@ -114,7 +114,7 @@ async def test_ingest_records_contact_links_account(ingest):
|
|
|
114
114
|
# the SDK's persistence privacy guard redacts email-shaped values.
|
|
115
115
|
assert contact.payload["email"] == "[REDACTED_EMAIL]"
|
|
116
116
|
assert request.relationships[0].relation_reference.endswith(
|
|
117
|
-
"
|
|
117
|
+
"relations/Contact/worksAtAccount"
|
|
118
118
|
)
|
|
119
119
|
|
|
120
120
|
|
|
@@ -133,7 +133,7 @@ async def test_ingest_records_opportunity_links_account(ingest):
|
|
|
133
133
|
)
|
|
134
134
|
assert opp.payload["stageName"] == "Won"
|
|
135
135
|
assert request.relationships[0].relation_reference.endswith(
|
|
136
|
-
"
|
|
136
|
+
"relations/Opportunity/opportunityForAccount"
|
|
137
137
|
)
|
|
138
138
|
|
|
139
139
|
|
|
@@ -160,14 +160,14 @@ def test_map_leads_converted_links():
|
|
|
160
160
|
async def test_retired_structural_alias_is_rejected(ingest):
|
|
161
161
|
service, _transport = ingest
|
|
162
162
|
with pytest.raises(IngestError, match="node_type"):
|
|
163
|
-
await
|
|
163
|
+
await STREAM.entities([{"id": "a", "type": "Account"}], ingest=service)
|
|
164
164
|
|
|
165
165
|
|
|
166
166
|
@pytest.mark.asyncio
|
|
167
167
|
async def test_empty_native_ingest_is_rejected(ingest):
|
|
168
168
|
service, _transport = ingest
|
|
169
169
|
with pytest.raises(IngestError, match="at least one entity"):
|
|
170
|
-
await
|
|
170
|
+
await STREAM.entities([], ingest=service)
|
|
171
171
|
|
|
172
172
|
|
|
173
173
|
@pytest.mark.asyncio
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pytest
|
|
2
|
+
import importlib.metadata
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
@pytest.mark.concept("SFDC-1.0")
|
|
@@ -7,7 +8,7 @@ def test_startup():
|
|
|
7
8
|
|
|
8
9
|
import salesforce_agent
|
|
9
10
|
|
|
10
|
-
assert re.fullmatch(r"\d+\.\d+\.\d+",
|
|
11
|
+
assert re.fullmatch(r"\d+\.\d+\.\d+", importlib.metadata.version("salesforce-agent"))
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@pytest.mark.concept("SFDC-1.0")
|
|
@@ -18,13 +19,3 @@ def test_core_surface_exposed():
|
|
|
18
19
|
assert callable(salesforce_agent.SalesforceAuth)
|
|
19
20
|
assert callable(salesforce_agent.SalesforceConfig)
|
|
20
21
|
assert callable(salesforce_agent.get_client)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@pytest.mark.concept("SFDC-1.0")
|
|
24
|
-
def test_mcp_server_entrypoints_importable():
|
|
25
|
-
from salesforce_agent.mcp_server import get_mcp_instance, mcp_server
|
|
26
|
-
|
|
27
|
-
assert callable(get_mcp_instance)
|
|
28
|
-
assert callable(mcp_server)
|
|
29
|
-
|
|
30
|
-
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"""CONCEPT:AU-ECO.messaging.native-backend-abstraction Unified ecosystem initialization dynamic check."""
|
|
2
|
-
|
|
3
|
-
import importlib
|
|
4
|
-
import inspect
|
|
5
|
-
from typing import Any
|
|
6
|
-
|
|
7
|
-
__version__ = "2.3.2"
|
|
8
|
-
__all__: list[str] = []
|
|
9
|
-
|
|
10
|
-
CORE_MODULES = [
|
|
11
|
-
"salesforce_agent.salesforce_response_models",
|
|
12
|
-
"salesforce_agent.salesforce_input_models",
|
|
13
|
-
"salesforce_agent.auth",
|
|
14
|
-
"salesforce_agent.api_client",
|
|
15
|
-
]
|
|
16
|
-
OPTIONAL_MODULES = {
|
|
17
|
-
"salesforce_agent.mcp_server": "mcp",
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _expose_members(module):
|
|
22
|
-
for name, obj in inspect.getmembers(module):
|
|
23
|
-
if (inspect.isclass(obj) or inspect.isfunction(obj)) and not name.startswith(
|
|
24
|
-
"_"
|
|
25
|
-
):
|
|
26
|
-
globals()[name] = obj
|
|
27
|
-
if name not in __all__:
|
|
28
|
-
__all__.append(name)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
for module_name in CORE_MODULES:
|
|
32
|
-
module = importlib.import_module(module_name)
|
|
33
|
-
_expose_members(module)
|
|
34
|
-
|
|
35
|
-
_loaded_optional_modules: dict[str, Any] = {}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _import_module_safely(module_name: str):
|
|
39
|
-
try:
|
|
40
|
-
return importlib.import_module(module_name)
|
|
41
|
-
except ImportError:
|
|
42
|
-
return None
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def __getattr__(name: str) -> Any:
|
|
46
|
-
if name == "_MCP_AVAILABLE":
|
|
47
|
-
mcp_key = next((k for k in OPTIONAL_MODULES if "mcp_server" in k), None)
|
|
48
|
-
return _import_module_safely(mcp_key) is not None if mcp_key else False
|
|
49
|
-
|
|
50
|
-
for module_name in OPTIONAL_MODULES:
|
|
51
|
-
if module_name not in _loaded_optional_modules:
|
|
52
|
-
module = _import_module_safely(module_name)
|
|
53
|
-
if module is not None:
|
|
54
|
-
_loaded_optional_modules[module_name] = module
|
|
55
|
-
_expose_members(module)
|
|
56
|
-
|
|
57
|
-
module = _loaded_optional_modules.get(module_name)
|
|
58
|
-
if module is not None and hasattr(module, name):
|
|
59
|
-
return getattr(module, name)
|
|
60
|
-
|
|
61
|
-
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def __dir__() -> list[str]:
|
|
65
|
-
return sorted(list(globals().keys()) + __all__)
|
|
File without changes
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_comment": "Tier-1 mcp_tool source presets for salesforce-agent (AU-KG.ingest.mcp-tool-connector). Syncs Salesforce CRM objects into the KG as documents via the salesforce-agent MCP server's salesforce_soql tool. Contributed presets win over the central MCP_TOOL_PRESETS. The native typed-node path is salesforce_ingest_crm / salesforce_agent.kg_ingest.",
|
|
3
|
-
"salesforce-accounts": {
|
|
4
|
-
"server": "salesforce-mcp",
|
|
5
|
-
"tool": "salesforce_soql_query",
|
|
6
|
-
"params": {
|
|
7
|
-
"soql": "SELECT Id, Name, Industry, Type, Website, Description FROM Account"
|
|
8
|
-
},
|
|
9
|
-
"records_path": "records",
|
|
10
|
-
"id_field": "Id",
|
|
11
|
-
"title_field": "Name",
|
|
12
|
-
"text_field": "Description",
|
|
13
|
-
"doc_type": "salesforce_account",
|
|
14
|
-
"params_style": "args"
|
|
15
|
-
},
|
|
16
|
-
"salesforce-opportunities": {
|
|
17
|
-
"server": "salesforce-mcp",
|
|
18
|
-
"tool": "salesforce_soql_query",
|
|
19
|
-
"params": {
|
|
20
|
-
"soql": "SELECT Id, Name, StageName, Amount, CloseDate, Description FROM Opportunity"
|
|
21
|
-
},
|
|
22
|
-
"records_path": "records",
|
|
23
|
-
"id_field": "Id",
|
|
24
|
-
"title_field": "Name",
|
|
25
|
-
"text_field": "Description",
|
|
26
|
-
"doc_type": "salesforce_opportunity",
|
|
27
|
-
"params_style": "args"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"""Main FastMCP server and tool registration for the Salesforce connector."""
|
|
2
|
-
|
|
3
|
-
import sys
|
|
4
|
-
from typing import Any
|
|
5
|
-
|
|
6
|
-
from agent_connector_sdk.config import load_config
|
|
7
|
-
from agent_connector_sdk.mcp.server import create_mcp_server
|
|
8
|
-
from agent_connector_sdk.mcp.tool_surface import register_tool_surface
|
|
9
|
-
from fastmcp.utilities.logging import get_logger
|
|
10
|
-
from starlette.requests import Request
|
|
11
|
-
from starlette.responses import JSONResponse
|
|
12
|
-
|
|
13
|
-
from salesforce_agent.api import (
|
|
14
|
-
AdminClient,
|
|
15
|
-
BulkClient,
|
|
16
|
-
DescribeClient,
|
|
17
|
-
QueryClient,
|
|
18
|
-
RecordsClient,
|
|
19
|
-
)
|
|
20
|
-
from salesforce_agent.auth import get_client
|
|
21
|
-
from salesforce_agent.mcp.mcp_salesforce import (
|
|
22
|
-
register_admin_tools,
|
|
23
|
-
register_bulk_tools,
|
|
24
|
-
register_describe_tools,
|
|
25
|
-
register_ingest_tools,
|
|
26
|
-
register_records_tools,
|
|
27
|
-
register_soql_tools,
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
__version__ = "2.3.2"
|
|
31
|
-
logger = get_logger(name="salesforce_agent")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _operation_targets() -> list[dict[str, Any]]:
|
|
35
|
-
"""One operation-tool group per resource client of the ``Api`` facade."""
|
|
36
|
-
resources = {
|
|
37
|
-
"soql": QueryClient,
|
|
38
|
-
"records": RecordsClient,
|
|
39
|
-
"describe": DescribeClient,
|
|
40
|
-
"bulk": BulkClient,
|
|
41
|
-
"admin": AdminClient,
|
|
42
|
-
}
|
|
43
|
-
return [
|
|
44
|
-
{
|
|
45
|
-
"client_cls": client_cls,
|
|
46
|
-
"get_client": (lambda name=name: getattr(get_client(), name)),
|
|
47
|
-
"prefix": f"salesforce_{name}",
|
|
48
|
-
}
|
|
49
|
-
for name, client_cls in resources.items()
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def get_mcp_instance() -> tuple[Any, ...]:
|
|
54
|
-
load_config()
|
|
55
|
-
args, mcp, middlewares = create_mcp_server(
|
|
56
|
-
name="Salesforce MCP",
|
|
57
|
-
version=__version__,
|
|
58
|
-
instructions=(
|
|
59
|
-
"Salesforce MCP Server — SOQL/SOSL queries, record CRUD with "
|
|
60
|
-
"composite/collections batching, metadata describe, Bulk API "
|
|
61
|
-
"2.0 ingest, and org administration. Destructive operations are "
|
|
62
|
-
"gated by SALESFORCE_ALLOW_DESTRUCTIVE."
|
|
63
|
-
),
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
@mcp.custom_route("/health", methods=["GET"])
|
|
67
|
-
async def health_check(request: Request) -> JSONResponse:
|
|
68
|
-
return JSONResponse({"status": "OK"})
|
|
69
|
-
|
|
70
|
-
register_tool_surface(
|
|
71
|
-
mcp,
|
|
72
|
-
service="salesforce-agent",
|
|
73
|
-
verbose_targets=_operation_targets(),
|
|
74
|
-
registrars=[
|
|
75
|
-
register_soql_tools,
|
|
76
|
-
register_records_tools,
|
|
77
|
-
register_describe_tools,
|
|
78
|
-
register_bulk_tools,
|
|
79
|
-
register_admin_tools,
|
|
80
|
-
register_ingest_tools,
|
|
81
|
-
],
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
for mw in middlewares:
|
|
85
|
-
mcp.add_middleware(mw)
|
|
86
|
-
return mcp, args, middlewares
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def mcp_server() -> None:
|
|
90
|
-
mcp, args, middlewares = get_mcp_instance()
|
|
91
|
-
print(f"Salesforce MCP v{__version__}", file=sys.stderr)
|
|
92
|
-
if args.transport == "streamable-http":
|
|
93
|
-
mcp.run(transport="streamable-http", host=args.host, port=args.port)
|
|
94
|
-
else:
|
|
95
|
-
mcp.run(transport="stdio")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if __name__ == "__main__":
|
|
99
|
-
mcp_server()
|
|
File without changes
|
|
File without changes
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
[agent_connector_sdk.connector]
|
|
2
|
-
salesforce-mcp = salesforce_agent
|
|
3
|
-
|
|
4
|
-
[agent_connector_sdk.ontology_providers]
|
|
5
|
-
salesforce-agent = salesforce_agent.ontology
|
|
6
|
-
|
|
7
|
-
[agent_connector_sdk.prompt_providers]
|
|
8
|
-
salesforce-agent = salesforce_agent.prompts
|
|
9
|
-
|
|
10
|
-
[agent_connector_sdk.skill_providers]
|
|
11
|
-
salesforce-agent = salesforce_agent.skills
|
|
12
|
-
|
|
13
|
-
[agent_connector_sdk.source_connector_providers]
|
|
14
|
-
salesforce-agent = salesforce_agent.connectors
|
|
15
|
-
|
|
16
|
-
[console_scripts]
|
|
17
|
-
salesforce-mcp = salesforce_agent.mcp_server:mcp_server
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"""CONN-SALESFORCE-AGENT-CONNECTOR-CONTENT-R001: the server lists its packaged skills, ontology and prompts by default."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import asyncio
|
|
6
|
-
import importlib
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
import pytest
|
|
10
|
-
from fastmcp import Client
|
|
11
|
-
|
|
12
|
-
PACKAGE = "salesforce_agent"
|
|
13
|
-
ROOT = Path(list(importlib.import_module(PACKAGE).__path__)[0])
|
|
14
|
-
|
|
15
|
-
pytestmark = pytest.mark.spec("CONN-SALESFORCE-AGENT-CONNECTOR-CONTENT-R001")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def _server():
|
|
19
|
-
namespace = {"__name__": PACKAGE + ".mcp_server"}
|
|
20
|
-
exec(
|
|
21
|
-
"from agent_connector_sdk.mcp.server import create_mcp_server\n"
|
|
22
|
-
"result = create_mcp_server('salesforce-mcp', version='0', command_args=[])",
|
|
23
|
-
namespace,
|
|
24
|
-
)
|
|
25
|
-
return namespace["result"][1]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
async def _listings():
|
|
29
|
-
async with Client(_server()) as client:
|
|
30
|
-
resources = {str(r.uri) for r in await client.list_resources()}
|
|
31
|
-
prompts = {p.name for p in await client.list_prompts()}
|
|
32
|
-
return resources, prompts
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def test_default_content_surfaces() -> None:
|
|
36
|
-
resources, prompts = asyncio.run(_listings())
|
|
37
|
-
if list(ROOT.glob("skills/*/SKILL.md")):
|
|
38
|
-
assert any(u.startswith("skill://") for u in resources)
|
|
39
|
-
if list(ROOT.glob("ontology/*.ttl")):
|
|
40
|
-
assert any(u.startswith("ontology://salesforce-mcp/") for u in resources)
|
|
41
|
-
for path in ROOT.glob("prompts/*.json"):
|
|
42
|
-
if not path.name.startswith("_"):
|
|
43
|
-
assert path.stem in prompts
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_describe.py
RENAMED
|
File without changes
|
|
File without changes
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/api/api_client_records.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/fixtures/records.json
RENAMED
|
File without changes
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/ontology/migrations/manifest.json
RENAMED
|
File without changes
|
|
File without changes
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/salesforce_input_models.py
RENAMED
|
File without changes
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent/salesforce_response_models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{salesforce_agent-2.3.2 → salesforce_agent-2.3.4}/salesforce_agent.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|